您的位置:

C++进程间通信

一、管道

1、管道概述

管道是一种基于内存的进程间通信方法,分为无名管道和有名管道。无名管道只能用于父子进程间通信,有名管道可用于任意进程间通信。

无名管道(匿名管道)实际上是一块内存缓冲区,严格遵循先进先出的原则。其中一个进程把数据写入缓冲区,另一个进程从缓冲区取出数据,读取和写入时分别用到管道的读端和写端。父进程调用fork之后,子进程的管道描述符和父进程完全独立。如果父进程调用了close,子进程并不会受到影响。另外,管道只能用于单向通信。

有名管道(FIFO)也是一种基于内存的进程通信方式,相对于无名管道可以用于任意进程间通信。有名管道存在于文件系统中,因此允许无亲缘关系进程间通信。

2、使用管道进行进程间通信

#include 
#include 
   
#include 
    

#define MSGSIZE 16

int main()
{
    char* msg = "Hello, world!";
    char inbuf[MSGSIZE];
    int p[2], pid;

    if (pipe(p) < 0) {
        fprintf(stderr, "pipe failed\n");
        exit(1);
    }

    if ((pid = fork()) > 0) {
        close(p[0]);
        write(p[1], msg, MSGSIZE);
        close(p[1]);
    } else if (pid == 0) {
        close(p[1]);
        read(p[0], inbuf, MSGSIZE);
        printf("%s\n", inbuf);
        close(p[0]);
    } else {
        fprintf(stderr, "fork failed\n");
        exit(2);
    }

    return 0;
}

    
   
  

二、消息队列

1、消息队列概述

消息队列是一种进程间通信的方式,进程可以通过消息队列来传递数据。消息队列在内核中维护,提供收发的缓存区,它是一种比较可靠的IPC机制。其中,每个消息都有一个类型属性,接收进程可以选择接收指定类型的消息。

2、使用消息队列进行进程间通信

#include 
#include 
   
#include 
    
#include 
     
#include 
      

#define MSGSZ 128

struct msgbuf {
    long mtype;
    char mtext[MSGSZ];
};

int main()
{
    int msqid;
    key_t key;
    struct msgbuf sndbuf, rcvbuf;

    if ((key = ftok(".", 'A')) == -1) {
        perror("ftok");
        exit(1);
    }

    if ((msqid = msgget(key, IPC_CREAT | 0666)) == -1) {
        perror("msgget");
        exit(1);
    }

    sndbuf.mtype = 1;
    sprintf(sndbuf.mtext, "hello, world!");
    if (msgsnd(msqid, &sndbuf, MSGSZ, IPC_NOWAIT) == -1) {
        perror("msgsnd");
        exit(1);
    }

    if (msgrcv(msqid, &rcvbuf, MSGSZ, 1, 0) == -1) {
        perror("msgrcv");
        exit(1);
    }
    printf("receive: %s\n", rcvbuf.mtext);

    if (msgctl(msqid, IPC_RMID, 0) == -1) {
        perror("msgctl");
        exit(1);
    }

    return 0;
}

      
     
    
   
  

三、信号量

1、信号量概述

信号量是一种进程间通信的方式,它用来保持多个进程之间同步或互斥。其中,信号量的值用来表示可用资源的个数,进程可以通过执行P操作(申请资源)和V操作(释放资源)来更改信号量的值。当信号量的值为0时,执行P操作的进程会进入阻塞状态。

2、使用信号量进行进程间通信

#include 
#include 
   
#include 
    
#include 
     
#include 
      

#define SEM_NUM 1

int main()
{
    key_t key;
    int semid, shmid;
    char *shmaddr;
    struct sembuf sembuf;

    if ((key = ftok(".", 'A')) == -1) {
        perror("ftok");
        exit(1);
    }

    if ((semid = semget(key, SEM_NUM, IPC_CREAT | 0666)) == -1) {
        perror("semget");
        exit(1);
    }

    if ((shmid = shmget(key, 1024, IPC_CREAT | 0666)) == -1) {
        perror("shmget");
        exit(1);
    }

    if ((shmaddr = shmat(shmid, NULL, 0)) == (void *)-1) {
        perror("shmat");
        exit(1);
    }

    sembuf.sem_num = 0;
    sembuf.sem_op = 1;
    sembuf.sem_flg = SEM_UNDO;
    semctl(semid, 0, SETVAL, 1);

    if (fork() == 0) {
        sembuf.sem_op = -1;
        semop(semid, &sembuf, 1);
        printf("child process write\n");
        sprintf(shmaddr, "hello, world!");
        sembuf.sem_op = 1;
        semop(semid, &sembuf, 1);
        exit(0);
    } else {
        sembuf.sem_op = -1;
        semop(semid, &sembuf, 1);
        printf("parent process read: %s\n", shmaddr);
        sembuf.sem_op = 1;
        semop(semid, &sembuf, 1);
    }

    return 0;
}

      
     
    
   
  

四、共享内存

1、共享内存概述

共享内存是一种高效的进程间通信方式,它通过将内存缓冲区映射到多个进程的虚拟地址空间,让多个进程之间共享数据。共享内存通常需要配合其他进程同步机制,如信号量一起使用。但存在一个问题,即多个进程共享内存容易引发数据一致性问题。

2、使用共享内存进行进程间通信

#include 
#include 
   
#include 
    
#include 
     

int main()
{
    int shmid, pid;
    char *shmaddr;

    if ((shmid = shmget(IPC_PRIVATE, 1024, IPC_CREAT | 0666)) == -1) {
        perror("shmid");
        exit(1);
    }

    if ((shmaddr = shmat(shmid, NULL, 0)) == (void *)-1) {
        perror("shmat");
        exit(1);
    }

    if ((pid = fork()) == 0) {
        printf("child process write\n");
        strcpy(shmaddr, "hello, world!");
        exit(0);
    } else if (pid > 0) {
        wait(NULL);
        printf("parent process read: %s\n", shmaddr);
    } else {
        perror("fork");
        exit(1);
    }

    if (shmctl(shmid, IPC_RMID, NULL) == -1) {
        perror("shmctl");
        exit(1);
    }

    return 0;
}