一、管道
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; }