进程间通信和同步: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\n", 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!\n");

        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\n");

        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\n");

        tell_parent();

    }

    else

    {

        wait_child();

        printf("parent: after child\n");

    }

    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\n", 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\n", 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\n”);

    if(msgctl(msqid, IPC_STAT, &buf) < 0)

    {

        perror("msgctl");

        exit(1);

    }

    printf("message queue # of messages is: %d\n", 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\n", msg1.mtext);

    

    if(msgctl(msqid, IPC_STAT, &buf) < 0)

    {

        perror("msgctl");

        exit(1);

    }

    printf("message queue # of messages is: %d\n", 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\n", 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!\n");

    }    

    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\n", shmc);

        shmdt(shmc);

    }



    return(0);

}
运行结果:

image

六、信号

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

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

你可能感兴趣的:(消息队列)