zoukankan      html  css  js  c++  java
  • 进程间通信和同步:pipe、FIFO、消息队列、信号量、共享内存、信号

    一、半双工管道(pipe)

    image

    关于管道详细介绍可参考http://www.cnblogs.com/nufangrensheng/p/3560130.html

    1、管道实现父子进程间通信实例:

    /* pipe.c */
    #include <unistd.h>
    #include <stdio.h>
    #include <limits.h>
    #include <sys/types.h>
    #include <errno.h>
    #include <stdlib.h>
    #define MAXLINE 1024
    int 
    main(void)
    {
        int fd[2], pid;
        char buf[MAXLINE];    
    
        if(pipe(fd) < 0)
        {
            perror("pipe error");
            exit(1);
        }
        
        if((pid = fork()) < 0)
        {
            perror("fork error");
            exit(1);
        }
        else if(pid == 0)    /* child */
        {
            close(fd[1]);    /* read from parent */
            
            if(read(fd[0], buf, MAXLINE) < 0)
            {
                perror("read error");
                exit(1);
            }
            printf("read from parent: %s
    ", buf);
        }
        else            /* parent */
        {
            close(fd[0]);    /* send to child */
            
            if(write(fd[1], "hello, i am your parent", 24) != 24)
            {
                perror("write error");
                exit(1);
            }
            printf("send to  child OK!
    ");
            wait(NULL);
        }
    }

    编译运行结果:

    image

    2、管道实现父子进程间同步实例:

    /* pipe_sync.c */
    #include <sys/types.h>
    #include <errno.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #define    BUFSIZE    1024
    
    int fd1[2], fd2[2];
    char c;
    
    void tell_wait()
    {
        if(pipe(fd1) < 0 || pipe(fd2) < 0)
        {
            perror("pipe error");
            exit(1);    
        }
    }
    
    void tell_parent()
    {
        if(write(fd1[1], "c", 1) != 1)
        {
            perror("write error");
            exit(1);
        }
    }
    void wait_parent()
    {
        if(read(fd2[0], &c, 1) != 1)
        {
            perror("read error");
            exit(1);
        }
        if(c != 'p')
        {
            printf("wait_parent: invalid data
    ");
            exit(1);
        }
    }
    void tell_child()
    {
        if(write(fd2[1], "p", 1) != 1)
        {
            perror("write error");
            exit(1);
        }
    }
    void wait_child()
    {
        if(read(fd1[0], &c, 1) != 1)
        {
            perror("read error");
            exit(1);
        }
        if(c != 'c')
        {
            printf("wait_child: invalid data");
            exit(1);
        }
    }
    
    int
    main(void)
    {
        int pid;
        tell_wait();
        if((pid = fork()) < 0)
        {
            perror("fork error");
            exit(1);
        }
        else if(pid == 0)
        {
            printf("child: first
    ");
            tell_parent();
        }
        else
        {
            wait_child();
            printf("parent: after child
    ");
        }
        return(0);
    }

    编译运行结果:

    image

     

    二、命名管道(FIFO)

    image

    在文件系统中命名管道是以设备特殊文件的形式存在的。

    不同的进程可以通过命名管道共享数据。

    关于FIFO详细介绍可参考http://www.cnblogs.com/nufangrensheng/p/3561632.html

    FIFO实现进程间通信实例:

    /***************************
    * **** FIFO server**********
    ***************************/
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    
    #define FIFO     "/home/zhu/network/fifo/myfifo"
    #define OPEN_MODE    O_RDONLY
    
    int
    main(void)
    {
        int fifofd;
        char buf[80];
    
        unlink(FIFO);  /* 防止FIFO已存在 */
       
     if(mkfifo(FIFO, 0777) == -1)
        {
            perror("mkfifo");
            exit(1);
        }
    
        if((fifofd = open(FIFO, OPEN_MODE)) < 0)
        {
            perror("open");
            exit(1);
        }
        
        read(fifofd, buf, sizeof(buf));
        printf("message from client: %s
    ", buf);
    
        close(fifofd);
    
        return(0);
    }
    /***************************
    * **** FIFO client**********
    ***************************/
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    
    #define FIFO     "/home/zhu/network/fifo/myfifo"
    #define OPEN_MODE    O_WRONLY
    int
    main(void)
    {
        int fifofd;
        char s[] = "hello,server!";
    
        if((fifofd = open(FIFO, OPEN_MODE)) < 0)
        {
            perror("open");
            exit(1);
        }
        
        write(fifofd, s, sizeof(s));
        printf("write message: %s
    ", s);
    
        close(fifofd);
    
        return(0);
    }

    编译成功后,我们首先运行服务器(创建FIFO,等待客户发来消息,此时FIFO服务器阻塞):

    image

    接着我们在另一个终端窗口运行客户程序,如下图所示,可以看出客户端已成功发送,服务器端也成功接收:

    image

     

    三、消息队列

    消息队列是内核地址空间中的内部链表,通过Linux内核在各个进程之间传递内容。

    关于消息队列详细介绍可参考http://www.cnblogs.com/nufangrensheng/p/3561820.html

    消息队列实现进程间通信实例:

    /***************************
    *******MSGQ server**********
    ***************************/
    #include <sys/msg.h>
    #include <sys/ipc.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    
    #define msqpath    "/home/zhu/network/msgqueue/msq"
    #define proj_id    'b'
    
    struct mymesg {
        long mtype;
        char mtext[512];    
    };
    
    int 
    main(void)
    {
        key_t key;
        int msqid;
        struct msqid_ds buf;    
        struct mymesg msg1;
        msg1.mtype = 1;
        sprintf(msg1.mtext, "hello");
    
        if((key = ftok(msqpath, proj_id)) < 0)
        {
            perror("ftok");
            exit(1);
        }
    
        if((msqid = msgget(key, IPC_CREAT)) < 0)
        {
            perror("msgget");
            exit(1);
        }     
        
        if(msgsnd(msqid, &msg1, sizeof(msg1), IPC_NOWAIT) < 0)
        {
            perror("msgsnd");
            exit(1);
        }
        printf(“send message : hello
    ”);
        if(msgctl(msqid, IPC_STAT, &buf) < 0)
        {
            perror("msgctl");
            exit(1);
        }
        printf("message queue # of messages is: %d
    ", buf.msg_qnum);
        return(0);
        
    }
    /*****************************
    **********MSGQ client*********
    *****************************/
    #include <sys/msg.h>
    #include <sys/ipc.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    
    #define msqpath    "/home/zhu/network/msgqueue/msq"
    #define proj_id    'b'
    
    struct mymesg {
        long mtype;
        char mtext[512];    
    };
    
    int 
    main(void)
    {
        key_t key;
        int msqid;
        struct msqid_ds buf;   
        struct mymesg msg1;
    
        if((key = ftok(msqpath, proj_id)) < 0)
        {
            perror("ftok");
            exit(1);
        }
    
        if((msqid = msgget(key, IPC_EXCL)) < 0)
        {
            perror("msgget");
            exit(1);
        }     
        
        if(msgrcv(msqid, &msg1, sizeof(msg1), 0, IPC_NOWAIT) < 0)
        {
            perror("msgrcv");
            exit(1);
        }
        printf("receive message : %s
    ", msg1.mtext);
        
        if(msgctl(msqid, IPC_STAT, &buf) < 0)
        {
            perror("msgctl");
            exit(1);
        }
        printf("message queue # of messages is: %d
    ", buf.msg_qnum);
        return(0);
        
    }

    编译后运行结果如下:

    image

     

    四、信号量

    信号量是一种计数器,用来控制对多个进程共享的资源所进行的访问。它们常常被用作一个锁机制,在某个进程正在对特定资源进行访问时,信号量可以防止另一个进程去访问它。

    关于信号量详细介绍可参考http://www.cnblogs.com/nufangrensheng/p/3562046.html

    信号量实现资源控制实例:

    #include <sys/types.h>
    #include <linux/sem.h>
    #include <linux/ipc.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <unistd.h>
    
    #define sempath    "/home/zhu/network/semaphore/sem"
    #define proj_id    'c'
    
    int
    main(void)
    {
        int semid, i;
        key_t    key;
        union semun sem, getsem;
        sem.val = 3;
    
        if((key = ftok(sempath, proj_id)) < 0)
        {
            perror("ftok");
            exit(1);
        }
        
        if((semid = semget(key, 1, IPC_CREAT)) < 0)
        {
            perror("semget");
            exit(1);
        }
        
        semctl(semid, 0, SETVAL, sem);
        
        semctl(semid, 0, GETVAL, sem);    
        printf("# of usable semphore: %d
    ", sem.val);
    
        struct sembuf sops = {0, -1, IPC_NOWAIT};
        for(i = 0; i < 4; i++)
        {
            printf(“%dth:”,i+1);
         fflush(stdout);
            if(semop(semid, &sops, 1) < 0)
            {
                perror("semop");
                exit(1);
            }
         printf("ask for one semaphore:success!
    ");
        }    
        return(0);
    }

    编译运行结果如下(因为我们把信号量值设置为3,所以第四次资源请求失败):

    image

    注意,在上面的程序中,包含的头文件#include <linux/sem.h> 和#include <linux/ipc.h>。而不是#include <sys/sem.h> #include <sys/ipc.h>。否则出现“storage of size of 'sem' isn't know”的错误。详细介绍请参考http://hi.baidu.com/yuhongyangcn/item/f52545b33c1b55a1eaba93ac

    关于POSIX信号量详情可参考http://www.cnblogs.com/nufangrensheng/p/3564306.html

    注意使用POSIX信号量时,除了要包含头文件<semaphore.h>外,在编译选项中还有加上-lrt选项,否则出现“undefined reference to”这样的编译错误。

    五、共享内存

    共享内存是在多个进程之间共享内存区域的一种进程间通信的方式,它是在多个进程间对内存段进行映射的方式实现内存共享的。这是最快的IPC方式。

    关于共享内存详细介绍可参考http://www.cnblogs.com/nufangrensheng/p/3563712.html

    共享内存实现父子进程间通信(这里为了简化、突出共享内存的使用方式,并没有加入同步处理,而只是简单地使用sleep模拟同步):

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <string.h>
    
    static char msg[] = "hello, share memory!";
    
    int 
    main(void)
    {
        key_t key;
        char i, *shms, *shmc;
        pid_t pid;
        int shmid;
        
        key = ftok("/home/zhu/network/shmm/shm", 'a');
    
        shmid = shmget(key, 1024, IPC_CREAT | 0604);
    
        pid = fork();
        if( pid > 0)
        {
            shms = (char *)shmat(shmid, 0, 0);
            memcpy(shms, msg, strlen(msg) + 1);
            sleep(5);
    
            shmdt(shms);
        }
        else if(pid == 0)
        {
            shmc = (char *)shmat(shmid, 0, 0);
            sleep(2);
            printf("the content in the share memory is : %s
    ", shmc);
            shmdt(shmc);
        }
    
        return(0);
    }
    运行结果:

    image

    六、信号

    信号(signal)机制是UNIX系统中最为古老的进程之间的通信机制。它用于在一个或多个进程之间传递异步信号。

    关于信号详细介绍可参考http://www.cnblogs.com/nufangrensheng/p/3514157.html

  • 相关阅读:
    JS中encodeURIComponent在PHP中实现的办法_tdweb的博客,仅仅是个博客_百度空间
    废弃的java 爬虫代码
    c#实现Javascript的encodeURIComponent()函数
    Encode query with Python
    Chunked decoding in python
    python implemention javascript encodeURIComponent
    Java MongoDB : Insert a document
    tar zcvf ./xxx.tar.gz ./directory
    MyStringUtils test
    application/xwwwformurlencoded
  • 原文地址:https://www.cnblogs.com/nufangrensheng/p/3579378.html
Copyright © 2011-2022 走看看