进程间通信方式详解:管道、命名管道、消息队列、共享内存、信号量
进程间通信方式有哪些?各举例实现一个demo
进程间通信(Inter-Process Communication,IPC)是指不同进程之间进行数据交换的方式,它允许不同的进程相互合作,完成共同的任务。常见的进程间通信方式有以下几种:
- 管道(Pipe)
管道是一种半双工的通信方式,只能在具有亲缘关系的进程之间使用,一般用于父子进程之间的通信。
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int fd[2];
pid_t pid;
char buf[1024];
if (pipe(fd) < 0) {
perror("pipe error");
exit(1);
}
if ((pid = fork()) < 0) {
perror("fork error");
exit(1);
} else if (pid > 0) { // 父进程
close(fd[0]); // 关闭读端
write(fd[1], 'hello world\n', 12);
} else { // 子进程
close(fd[1]); // 关闭写端
read(fd[0], buf, 1024);
printf('%s', buf);
}
return 0;
}
- 命名管道(Named Pipe)
命名管道是一种半双工的通信方式,可以在不具有亲缘关系的进程之间使用,一般用于客户端与服务器之间的通信。
// 服务端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fd;
char buf[1024];
if (mkfifo('fifo', 0666) < 0) { // 创建命名管道
perror("mkfifo error");
exit(1);
}
if ((fd = open('fifo', O_RDONLY)) < 0) { // 打开命名管道
perror("open error");
exit(1);
}
read(fd, buf, 1024);
printf('%s', buf);
close(fd);
return 0;
}
// 客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fd;
if ((fd = open('fifo', O_WRONLY)) < 0) { // 打开命名管道
perror("open error");
exit(1);
}
write(fd, 'hello world\n', 12);
close(fd);
return 0;
}
- 消息队列(Message Queue)
消息队列是一种异步的通信方式,可以在不具有亲缘关系的进程之间使用。
// 发送方
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
struct msgbuf {
long mtype;
char mtext[1024];
};
int main()
{
int msqid;
struct msgbuf buf;
key_t key;
if ((key = ftok('.', 'a')) < 0) { // 创建key
perror("ftok error");
exit(1);
}
if ((msqid = msgget(key, IPC_CREAT | 0666)) < 0) { // 创建消息队列
perror("msgget error");
exit(1);
}
buf.mtype = 1; // 消息类型
strcpy(buf.mtext, 'hello world');
if (msgsnd(msqid, &buf, strlen(buf.mtext), 0) < 0) { // 发送消息
perror("msgsnd error");
exit(1);
}
return 0;
}
// 接收方
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
struct msgbuf {
long mtype;
char mtext[1024];
};
int main()
{
int msqid;
struct msgbuf buf;
key_t key;
if ((key = ftok('.', 'a')) < 0) { // 创建key
perror("ftok error");
exit(1);
}
if ((msqid = msgget(key, IPC_CREAT | 0666)) < 0) { // 创建消息队列
perror("msgget error");
exit(1);
}
if (msgrcv(msqid, &buf, 1024, 1, 0) < 0) { // 接收消息
perror("msgrcv error");
exit(1);
}
printf('%s', buf.mtext);
if (msgctl(msqid, IPC_RMID, NULL) < 0) { // 删除消息队列
perror("msgctl error");
exit(1);
}
return 0;
}
- 共享内存(Shared Memory)
共享内存是一种高效的通信方式,可以实现多个进程之间的数据共享。
// 写进程
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
struct shared_mem {
int flag;
char buf[1024];
};
int main()
{
int shmid;
struct shared_mem *shmptr;
key_t key;
if ((key = ftok('.', 'a')) < 0) { // 创建key
perror("ftok error");
exit(1);
}
if ((shmid = shmget(key, sizeof(struct shared_mem), IPC_CREAT | 0666)) < 0) { // 创建共享内存
perror("shmget error");
exit(1);
}
if ((shmptr = (struct shared_mem *)shmat(shmid, NULL, 0)) == (void *)-1) { // 将共享内存映射到进程的地址空间中
perror("shmat error");
exit(1);
}
while (1) {
if (shmptr->flag == 0) {
fgets(shmptr->buf, sizeof(shmptr->buf), stdin);
shmptr->flag = 1;
}
}
if (shmdt(shmptr) < 0) { // 解除共享内存映射
perror("shmdt error");
exit(1);
}
return 0;
}
// 读进程
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
struct shared_mem {
int flag;
char buf[1024];
};
int main()
{
int shmid;
struct shared_mem *shmptr;
key_t key;
if ((key = ftok('.', 'a')) < 0) { // 创建key
perror("ftok error");
exit(1);
}
if ((shmid = shmget(key, sizeof(struct shared_mem), IPC_CREAT | 0666)) < 0) { // 创建共享内存
perror("shmget error");
exit(1);
}
if ((shmptr = (struct shared_mem *)shmat(shmid, NULL, 0)) == (void *)-1) { // 将共享内存映射到进程的地址空间中
perror("shmat error");
exit(1);
}
while (1) {
if (shmptr->flag == 1) {
printf('%s', shmptr->buf);
shmptr->flag = 0;
}
}
if (shmdt(shmptr) < 0) { // 解除共享内存映射
perror("shmdt error");
exit(1);
}
return 0;
}
- 信号量(Semaphore)
信号量是一种用于进程间同步和互斥的机制。
// 写进程
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
int main()
{
int semid;
struct sembuf semops;
key_t key;
if ((key = ftok('.', 'a')) < 0) { // 创建key
perror("ftok error");
exit(1);
}
if ((semid = semget(key, 1, IPC_CREAT | 0666)) < 0) { // 创建信号量
perror("semget error");
exit(1);
}
semops.sem_num = 0;
semops.sem_op = 1; // 信号量加1
semops.sem_flg = SEM_UNDO;
while (1) {
semop(semid, &semops, 1); // 发送信号量
sleep(1);
}
return 0;
}
// 读进程
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
int main()
{
int semid;
struct sembuf semops;
key_t key;
if ((key = ftok('.', 'a')) < 0) { // 创建key
perror("ftok error");
exit(1);
}
if ((semid = semget(key, 1, IPC_CREAT | 0666)) < 0) { // 创建信号量
perror("semget error");
exit(1);
}
semops.sem_num = 0;
semops.sem_op = -1; // 信号量减1
semops.sem_flg = SEM_UNDO;
while (1) {
semop(semid, &semops, 1); // 接收信号量
printf('hello world\n');
}
return 0;
}
除了以上几种常见的进程间通信方式,还有其他一些方法,例如:
- 套接字(Socket):套接字是网络编程中的一个概念,它可以用于进程间通信,即使是在不同主机上的进程之间。
- 信号(Signal):信号是一种异步的通信方式,可以用于进程间通信,但只能传递简单的信号,不能传递数据。
- 共享文件(Shared File):共享文件可以用于进程间通信,但效率比较低。
选择哪种进程间通信方式取决于具体的应用场景。例如,如果需要在父子进程之间进行简单的通信,可以选择管道;如果需要在不具有亲缘关系的进程之间进行数据交换,可以选择消息队列或共享内存;如果需要进行进程同步或互斥,可以选择信号量。
总结
进程间通信是多进程编程中不可缺少的一部分,它允许不同的进程相互合作,完成共同的任务。选择合适的进程间通信方式可以提高程序的性能和效率。
原文地址: https://www.cveoy.top/t/topic/mR4e 著作权归作者所有。请勿转载和采集!