進程間通訊和同步:pipe、FIFO、消息隊列、信號量、共享內存、信號

1、半雙工管道(pipe)

image

關於管道詳細介紹可參考http://www.cnblogs.com/nufangrensheng/p/3560130.htmlhtml

一、管道實現父子進程間通訊實例:linux

/* 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

二、管道實現父子進程間同步實例:異步

/* 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);
}

編譯運行結果:spa

image

 

2、命名管道(FIFO)

image

在文件系統中命名管道是以設備特殊文件的形式存在的。3d

不一樣的進程能夠經過命名管道共享數據。code

關於FIFO詳細介紹可參考http://www.cnblogs.com/nufangrensheng/p/3561632.htmlserver

FIFO實現進程間通訊實例:htm

/***************************
* **** 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服務器阻塞):blog

image

接着咱們在另外一個終端窗口運行客戶程序,以下圖所示,能夠看出客戶端已成功發送,服務器端也成功接收:

image

 

3、消息隊列

消息隊列是內核地址空間中的內部鏈表,經過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

 

4、信號量

信號量是一種計數器,用來控制對多個進程共享的資源所進行的訪問。它們經常被用做一個鎖機制,在某個進程正在對特定資源進行訪問時,信號量能夠防止另外一個進程去訪問它。

關於信號量詳細介紹可參考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」這樣的編譯錯誤。

5、共享內存

共享內存是在多個進程之間共享內存區域的一種進程間通訊的方式,它是在多個進程間對內存段進行映射的方式實現內存共享的。這是最快的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

6、信號

信號(signal)機制是UNIX系統中最爲古老的進程之間的通訊機制。它用於在一個或多個進程之間傳遞異步信號。

關於信號詳細介紹可參考http://www.cnblogs.com/nufangrensheng/p/3514157.html

相關文章
相關標籤/搜索