C++在Linux如何实现进程间通信
在Linux中,C++可以通过多种方式实现进程间通信(IPC)
当多个进程需要协同工作时,进程间通信(IPC)就成了绕不开的话题。在Linux环境下,C++开发者手头有不少成熟的IPC机制可供选择,每种都有其特定的适用场景和性能特点。理解这些机制,就像是掌握了让进程“对话”的不同语言。
免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

下面,我们就来梳理一下几种最常用的IPC方式:
管道(Pipes):
- 匿名管道(Anonymous Pipes): 这是最基础的管道形式,通常用于具有父子关系的进程之间进行单向通信。它就像一个临时的、无形的数据通道。
- 命名管道(Named Pipes, FIFOs): 与匿名管道不同,命名管道在文件系统中有一个可见的路径名。这样一来,任何知道这个名字的进程,无论是否有亲缘关系,都能通过它进行通信,灵活性大大增强。
信号(Signals):
- 信号更像是一种“通知”机制,用于异步地告知接收进程某个特定事件已经发生。它的处理方式简单直接,但携带的信息量有限。
消息队列(Message Queues):
- 如果进程间的对话需要更结构化的信息,消息队列是个不错的选择。它允许进程将格式化的消息放入队列,或从队列中读取,支持多个进程读写,并能根据消息类型进行筛选。
共享内存(Shared Memory):
- 说到速度,共享内存往往是冠军。它允许多个进程映射并访问同一块物理内存区域,数据交换直接在内存中进行,省去了内核态与用户态之间的数据拷贝开销,效率极高。
信号量(Semaphores):
- 当多个进程需要安全地访问共享资源(比如一块共享内存)时,信号量就派上用场了。它本质上是一个计数器,用于实现进程间的同步与互斥,防止出现竞态条件。
套接字(Sockets):
- 套接字的能力最为全面。它不仅能用于网络上不同主机间的通信,通过本地套接字(如Unix Domain Socket)也能实现同一台机器上进程间的高效数据交换,兼具通用性和高性能。
光说不练假把式。接下来,我们通过几段简洁的示例代码,来看看这些机制在C++中是如何落地的。
匿名管道示例(父子进程通信)
#include
#include
#include
#include
int main() {
int pipefd[2];
pid_t pid;
char buffer[10];
// 创建管道
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
// 创建子进程
pid = fork();
if (pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid == 0) { // 子进程
close(pipefd[1]); // 关闭写端
read(pipefd[0], buffer, sizeof(buffer)); // 读取消息
std::cout << "Child received: " << buffer << std::endl;
close(pipefd[0]);
} else { // 父进程
close(pipefd[0]); // 关闭读端
const char* message = "Hello from parent!";
write(pipefd[1], message, strlen(message) + 1); // 发送消息
close(pipefd[1]);
wait(NULL); // 等待子进程结束
}
return 0;
}
命名管道示例
#include
#include
#include
#include
int main() {
const char* fifo = "/tmp/myfifo";
mkfifo(fifo, 0666);
int fd = open(fifo, O_WRONLY);
if (fd == -1) {
perror("open");
return 1;
}
const char* message = "Hello from FIFO!";
write(fd, message, strlen(message) + 1);
close(fd);
unlink(fifo); // 删除命名管道
return 0;
}
共享内存示例
#include
#include
#include
#include
int main() {
key_t key = ftok("shmfile", 65);
int shmid = shmget(key, 1024, 0666|IPC_CREAT);
char *str = (char*) shmat(shmid, (void*)0, 0);
strcpy(str, "Hello world!");
std::cout << "String in shared memory: " << str << std::endl;
shmdt(str);
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
信号量示例
#include
#include
#include
#include
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
};
int main() {
key_t key = ftok("semfile", 65);
int semid = semget(key, 1, 0666|IPC_CREAT);
union semun arg;
arg.val = 1; // 初始化信号量为1
semctl(semid, 0, SETVAL, arg);
// 使用信号量进行同步操作
// ...
semctl(semid, 0, IPC_RMID); // 删除信号量集
return 0;
}
套接字示例(本地套接字)
// 服务器端
#include
#include
#include
#include
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
// 创建套接字文件描述符
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 绑定套接字到端口
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
// 接受连接
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
// 读取数据
char buffer[1024] = {0};
read(new_socket, buffer, 1024);
std::cout << "Message from client: " << buffer << std::endl;
// 发送响应
send(new_socket, "Hello from server", 17, 0);
std::cout << "Hello message sent\n";
close(new_socket);
close(server_fd);
return 0;
}
// 客户端
#include
#include
#include
#include
int main() {
int sock = 0;
struct sockaddr_in serv_addr;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
std::cout << " Socket creation error ";
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
// 将IPv4地址从文本转换为二进制形式
if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
std::cout << "Invalid address/ Address not supported ";
return -1;
}
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
std::cout << "Connection Failed ";
return -1;
}
send(sock, "Hello from client", 17, 0);
std::cout << "Hello message sent\n";
char buffer[1024] = {0};
read(sock, buffer, 1024);
std::cout << "Message from server: " << buffer << std::endl;
close(sock);
return 0;
}
看到这里,你可能已经发现了,这些IPC机制虽然强大,但并非没有挑战。尤其是在使用共享内存这类高效方式时,同步和互斥问题必须妥善处理,否则竞态条件和数据不一致就会找上门来。此外,扎实的错误处理逻辑和及时的资源清理(如关闭文件描述符、删除IPC对象)也是编写健壮IPC代码不可或缺的一环。把这些细节做到位,进程间的协作才能既高效又可靠。
相关攻略
Linux系统中 PhpStorm 版本控制实操指南 想在Linux环境下,把PhpStorm和Git玩得转,让代码管理既高效又省心?这份实操指南,就是为你准备的。咱们不绕弯子,直接切入正题,从环境配置到高阶技巧,一步步来。 一、环境准备与 Git 配置 万事开头难,先把基础环境搭好。这事儿分几步走
Linux 上 PHPStorm 性能优化实用指南 想让 PHPStorm 在 Linux 上跑得又快又稳?其实,这不仅仅是调整几个参数那么简单,而是一套从 IDE 内部到系统底层,再到日常工作流的组合拳。下面这份指南,就为你梳理了那些真正有效的优化策略。 一 IDE 设置优化 先从 IDE 本身入
Linux下配置 PHPStorm 环境 一 安装前准备 在动手安装之前,有几项准备工作必不可少。这就像盖房子前得先打好地基,能让你后续的步骤顺畅不少。 首先,更新你的系统并安装一些常用依赖。以 Debian 或 Ubuntu 为例,打开终端,执行这条命令就行:sudo apt update &&
核心原理 简单来说,HDFS的数据校验机制,就像给每一份数据都配上了一把专属的“指纹锁”。它的核心工作流程是这样的:在数据写入时,系统会为所有数据计算一个校验和;等到读取时,再重新计算一遍进行比对。这套机制的主要目的,就是为了捕捉在传输或存储过程中可能发生的位翻转等数据损坏问题。 技术上,它采用的是
HDFS读操作流程解析 说起大数据存储,HDFS(Hadoop分布式文件系统)绝对是绕不开的核心。它天生就是为了海量数据而生,设计上高度容错,能跨集群节点高效处理数据。那么,当客户端想从HDFS里读取文件时,背后究竟是怎样一套精密的流程在运作呢? 下面,我们就来一步步拆解这个看似复杂、实则逻辑清晰的
热门专题
热门推荐
卡尔达诺ADA:行情监控与高效投资指南 在加密货币市场,卡尔达诺(ADA)的价格走势一直是投资者关注的焦点。其价格波动不仅牵动人心,更直接关系到投资决策的成败。根据最新行情,ADA的价格约为0 801253美元(数据仅供参考,市场实时变化)。想要精准把握这样的波动,一款得力的工具必不可少。接下来要介
Debian上排查与修复Ja va运行时错误的实用流程 遇到Ja va程序在Debian上跑不起来,先别急着抓狂。这事儿其实有章可循,按照一套清晰的流程走下来,大部分问题都能迎刃而解。下面这份指南,就帮你把从快速定位到深度诊断的路径,都梳理清楚了。 一 快速定位与通用修复 排查的第一步,往往是那些最
松下电动剃须刀刀头更换全指南:自己动手,其实很简单 很多朋友可能不知道,手上那台松下电动剃须刀的刀头,其实完全可以自己拆卸和更换,根本不需要专门跑一趟维修点。这可不是什么“民间偏方”,而是松下官方设计的一部分。从ES8953到ES9932C、ES5821这些主流型号,刀网底座和内刀片都采用了模块化的
传真机如何实现多页连续复印?掌握专业设备的核心技巧 当你需要将多份纸质文件快速复印成多份副本时,一台具备复印功能的传真一体机是理想的办公伙伴。其核心便利性主要依赖于设备顶部的自动进纸器(ADF)。无论是佳博、松下还是兄弟等主流商用品牌,其多数型号均标配此功能。操作流程非常简便:只需将整理好的多页原稿
红米Note9 5G后盖如何完美还原?专业级无损复原全攻略 如何将拆开的红米Note9 5G手机后盖完美装回,实现如原厂般的严丝合缝?这看似简单的操作,实则需要精湛的工艺和细致的流程。对于经验丰富的维修工程师而言,确实可以做到近乎无损的复原。但对于缺乏专业知识的普通用户,若误以为仅是简单扣合,则极易





