当前位置: 首页 > news >正文

Linux 进程间通信(IPC)

进程间通信(IPC)是指不同进程之间交换数据或信息的机制。在 Unix/Linux 系统中,有多种进程间通信的方式,包括 管道(Pipe)消息队列(Message Queue)共享内存(Shared Memory)信号量(Semaphore) 等。

1. 管道(Pipe)

管道是 Unix/Linux 中最常见的进程间通信方式之一。它允许一个进程将数据写入管道,另一个进程从管道中读取数据。管道通常用于父子进程之间的通信。

示例:父进程和子进程通过管道通信
#include <stdio.h>
#include <unistd.h>
#include <string.h>int main() {int pipefd[2];pid_t pid;char buffer[128];// 创建管道if (pipe(pipefd) == -1) {perror("pipe failed");return 1;}pid = fork();  // 创建子进程if (pid == -1) {perror("fork failed");return 1;}if (pid == 0) {  // 子进程close(pipefd[0]);  // 关闭读取端const char *msg = "Hello from child process!";write(pipefd[1], msg, strlen(msg) + 1);  // 向管道写入数据close(pipefd[1]);} else {  // 父进程close(pipefd[1]);  // 关闭写入端read(pipefd[0], buffer, sizeof(buffer));  // 从管道读取数据printf("Parent received: %s\n", buffer);close(pipefd[0]);}return 0;
}
解释:
  • pipe(pipefd) 创建一个管道,其中 pipefd[0] 是读取端,pipefd[1] 是写入端。
  • 父进程和子进程通过 fork() 创建,父进程从管道中读取数据,子进程向管道写入数据。
  • write()read() 分别用于写入和读取管道数据。

2. 消息队列(Message Queue)

消息队列是一个允许进程通过向队列中发送和接收消息来交换信息的机制。它提供了一种可靠的、灵活的通信方式,可以用来实现复杂的进程间通信。

示例:使用消息队列进行进程间通信
#include <stdio.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>#define MSG_SIZE 128// 消息结构体
struct message {long msg_type;char msg_text[MSG_SIZE];
};int main() {key_t key = ftok("msgfile", 65);  // 创建消息队列的键值int msgid = msgget(key, 0666 | IPC_CREAT);  // 获取消息队列IDif (msgid == -1) {perror("msgget failed");return 1;}pid_t pid = fork();  // 创建子进程if (pid == -1) {perror("fork failed");return 1;}if (pid == 0) {  // 子进程发送消息struct message msg;msg.msg_type = 1;strcpy(msg.msg_text, "Hello from child process!");if (msgsnd(msgid, &msg, sizeof(msg), 0) == -1) {perror("msgsnd failed");return 1;}printf("Child sent message: %s\n", msg.msg_text);} else {  // 父进程接收消息struct message msg;if (msgrcv(msgid, &msg, sizeof(msg), 1, 0) == -1) {perror("msgrcv failed");return 1;}printf("Parent received message: %s\n", msg.msg_text);}// 删除消息队列msgctl(msgid, IPC_RMID, NULL);return 0;
}
解释:
  • msgget() 创建一个消息队列,msgsnd() 用于发送消息,msgrcv() 用于接收消息。
  • 父进程和子进程通过消息队列进行通信,子进程发送消息,父进程接收并打印。

3. 共享内存(Shared Memory)

共享内存允许多个进程访问同一块内存区域,提供高效的进程间通信方式。可以通过共享内存来交换数据,无需通过内核中转。

示例:父进程和子进程通过共享内存通信
#include <stdio.h>
#include <sys/shm.h>
#include <unistd.h>
#include <string.h>#define SHM_SIZE 128int main() {key_t key = ftok("shmfile", 65);  // 创建共享内存的键值int shm_id = shmget(key, SHM_SIZE, 0666 | IPC_CREAT);  // 获取共享内存IDif (shm_id == -1) {perror("shmget failed");return 1;}char *shm_ptr = shmat(shm_id, NULL, 0);  // 将共享内存映射到进程地址空间if (shm_ptr == (char *) -1) {perror("shmat failed");return 1;}pid_t pid = fork();  // 创建子进程if (pid == -1) {perror("fork failed");return 1;}if (pid == 0) {  // 子进程写入共享内存const char *msg = "Hello from child process!";strcpy(shm_ptr, msg);  // 写入数据到共享内存} else {  // 父进程读取共享内存sleep(1);  // 确保子进程先写入数据printf("Parent received: %s\n", shm_ptr);}// 分离共享内存shmdt(shm_ptr);// 删除共享内存shmctl(shm_id, IPC_RMID, NULL);return 0;
}
解释:
  • shmget() 创建一个共享内存段,shmat() 将共享内存附加到进程的地址空间。
  • 父进程和子进程通过共享内存进行数据交换。
  • shmdt()shmctl() 分别用于分离和删除共享内存。

4. 信号量(Semaphore)

信号量用于控制多个进程对共享资源的访问,常用于解决同步和互斥问题。

示例:使用信号量进行同步(此处示例比较简化)
#include <stdio.h>
#include <sys/sem.h>
#include <unistd.h>int main() {key_t key = ftok("semfile", 65);int sem_id = semget(key, 1, 0666 | IPC_CREAT);if (sem_id == -1) {perror("semget failed");return 1;}struct sembuf sb = {0, -1, 0};  // 信号量P操作pid_t pid = fork();  // 创建子进程if (pid == -1) {perror("fork failed");return 1;}if (pid == 0) {  // 子进程semop(sem_id, &sb, 1);  // 等待信号量printf("Child process has acquired the semaphore!\n");} else {  // 父进程sleep(1);  // 等待子进程sb.sem_op = 1;  // 信号量V操作semop(sem_id, &sb, 1);  // 释放信号量printf("Parent process has released the semaphore!\n");}semctl(sem_id, 0, IPC_RMID);  // 删除信号量return 0;
}
解释:
  • semget() 创建信号量,semop() 用于对信号量进行操作。
  • 父子进程通过信号量进行同步,控制对资源的访问。

总结

在 Unix/Linux 系统中,常见的进程间通信方式包括:

  • 管道(Pipe):父子进程之间通过管道传输数据。
  • 消息队列(Message Queue):进程间传递消息,可以支持多个进程通信。
  • 共享内存(Shared Memory):多个进程直接访问共享内存区。
  • 信号量(Semaphore):用于进程间的同步和互斥控制。

如果需要高效的数据交换,共享内存 是一个非常好的选择。如果需要管理多个进程之间的消息,消息队列 可能更适合。

http://www.dtcms.com/a/362264.html

相关文章:

  • Android14 init.rc各个阶段的主要操作
  • authentication port-control auto 和 dot1x port-control auto
  • Shell 编程:正则表达式与文本处理器
  • 软考-操作系统-错题收集(1)进程P的页面变换
  • 分布式一致性算法相关
  • 【Audio】切换至静音或振动模式时媒体音自动置 0
  • 基于SpringBoot+MYSQL开发的师生成果管理系统
  • 解锁Git仓库瘦身秘籍,git-sizer真香警告
  • Next.js渲染模式:SSR、SSG与ISR揭秘
  • Python实现点云渲染可视化杂记(直接、彩虹渐变、柱状、饼状和T-SNE赋色)
  • The Algorithmic Foundations of Differential Privacy - 2
  • 8Lane V-by-One HS LVDS FMC Card
  • 【开题答辩全过程】以 智慧药店管理系统的实现与设计为例,包含答辩的问题和答案
  • 基于单片机智能空调/温度控制系统
  • GaussDB 集群故障cm_ctl: can‘t connect to cm_server
  • API安全厂商F5首发后量子加密方案,为企业后量子时代加固防线
  • Java中方法的参数传递
  • TFT屏幕:STM32硬件SPI+DMA+队列自动传输
  • 【无标题】训练、推理适用的数据类型
  • C++ 学习与 CLion 使用:(五)数据类型,包括整型、实型、字符型、转义字符、字符串、布尔型
  • 椭圆曲线的数学基础
  • 【算法专题训练】17、双向链表
  • openEuler2403部署Redis8集群
  • AI推理方法演进:Chain-of-Thought、Tree-of-Thought与Graph-of-Thought技术对比分析
  • Spring 控制器参数注解
  • LangGraph 边(Edge)机制完全指南
  • Java 不支持在非静态内部类中声明静态 Static declarations in inner classes are not supported异常处理
  • 2025我“生发”了『折行』|『内注』|『终端正偿』|『中文负偿』四大“邪术”(前二造福python代码阅读者;后二助力所有艺术人)
  • nrf52840 解锁
  • 2025年09月01日Github流行趋势