首页 游戏 软件 资讯 排行榜 专题
首页
编程语言
C++在Linux下如何进行进程间通信

C++在Linux下如何进行进程间通信

热心网友
64
转载
2026-05-03

C++在Linux下如何进行进程间通信

C++在Linux下如何进行进程间通信

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

在Linux环境下开发C++程序,进程间通信(IPC)是个绕不开的话题。当多个进程需要协同工作、交换数据时,Linux系统提供了多种成熟的方案。每种方案都有其独特的“性格”和适用场景,理解它们的差异,是写出高效、稳定程序的关键。接下来,我们就逐一拆解这些常用的IPC方法。

1. 管道(Pipes)

管道算得上是Linux IPC的“元老”了,它提供了一种半双工的通信方式。什么叫半双工?简单说,就是数据只能单向流动。这种机制在父子进程之间尤其好用,因为它直接继承了文件描述符,创建和使用都非常直观。

无名管道(Anonymous Pipes)

无名管道,顾名思义,它没有名字,生命周期随进程结束而终结。它最大的特点就是只能在具有亲缘关系的进程(比如父子进程)间使用。其工作原理是:先调用pipe()系统调用创建一个管道,这会返回两个文件描述符,一个用于读,一个用于写。父进程fork()出子进程后,双方各自关闭不需要的一端,就能建立起一条单向的数据通道。

#include 
#include 
#include 
#include 

int main() {
    int pipefd[2];
    pid_t pid;
    char buffer[256];

    // 创建管道
    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;
}

命名管道(Named Pipes, FIFOs)

无名管道好用,但限制也明显——只能用于亲缘进程。这时候,命名管道(FIFO)就派上用场了。它在文件系统中有一个路径名,任何知道这个路径的进程都可以打开它进行读写,完全解除了亲缘关系的束缚。你可以把它想象成一个有名字的、先进先出的特殊文件。

#include 
#include 
#include 
#include 
#include 

int main() {
    const char* fifo_name = "/tmp/myfifo";
    int fd;
    char buffer[256];

    // 创建命名管道
    if (mkfifo(fifo_name, 0666) == -1) {
        perror("mkfifo");
        exit(EXIT_FAILURE);
    }

    fd = open(fifo_name, O_RDWR);
    if (fd == -1) {
        perror("open");
        exit(EXIT_FAILURE);
    }

    // 写入数据
    const char* message = "Hello from FIFO";
    write(fd, message, strlen(message) + 1);

    // 读取数据
    read(fd, buffer, sizeof(buffer));
    std::cout << "Received: " << buffer << std::endl;

    close(fd);
    unlink(fifo_name); // 删除命名管道
    return 0;
}

2. 消息队列(Message Queues)

如果说管道是字节流,那么消息队列就是“快递柜”。它允许进程以结构化的消息为单位进行数据交换,每条消息都有类型标识。发送方和接收方可以基于消息类型进行选择性接收,这提供了比管道更灵活的通信模式。消息队列独立于进程存在,即使通信进程结束了,消息仍然可以保留在队列中。

#include 
#include 
#include 
#include 
#include 

struct msg_buffer {
    long mtype;
    char mtext[100];
};

int main() {
    key_t key = ftok("msgqueue_example.c", 65);
    int msgid = msgget(key, 0666 | IPC_CREAT);
    if (msgid == -1) {
        perror("msgget");
        exit(EXIT_FAILURE);
    }

    msg_buffer buffer;
    buffer.mtype = 1;
    strcpy(buffer.mtext, "Hello from message queue");

    // 发送消息
    if (msgsnd(msgid, &buffer, sizeof(buffer.mtext), 0) == -1) {
        perror("msgsnd");
        exit(EXIT_FAILURE);
    }

    // 接收消息
    if (msgrcv(msgid, &buffer, sizeof(buffer.mtext), 1, 0) == -1) {
        perror("msgrcv");
        exit(EXIT_FAILURE);
    }

    std::cout << "Received message: " << buffer.mtext << std::endl;
    msgctl(msgid, IPC_RMID, NULL); // 删除消息队列
    return 0;
}

3. 共享内存(Shared Memory)

追求极致性能?那共享内存绝对是你的首选。它的原理很直接:在内存中划出一块区域,让多个进程都能映射到自己的地址空间。这样一来,进程间的数据交换就变成了直接对内存的读写,完全避免了内核缓冲区的数据拷贝,速度自然是最快的。但天下没有免费的午餐,共享内存不提供任何同步机制,需要配合信号量等工具来防止数据竞争。

#include 
#include 
#include 
#include 
#include 

int main() {
    key_t key = ftok("shm_example.c", 65);
    int shmid = shmget(key, 1024, 0666 | IPC_CREAT);
    if (shmid == -1) {
        perror("shmget");
        exit(EXIT_FAILURE);
    }

    char* str = (char*) shmat(shmid, (void*)0, 0);
    if (str == (char*)(-1)) {
        perror("shmat");
        exit(EXIT_FAILURE);
    }

    strcpy(str, "Hello from shared memory");
    std::cout << "Message written in memory: " << str << std::endl;

    shmdt(str); // 分离共享内存
    // 删除共享内存
    shmctl(shmid, IPC_RMID, NULL);
    return 0;
}

4. 信号量(Semaphores)

严格来说,信号量本身并不是为了传递数据,而是为了解决一个更根本的问题:进程同步。当多个进程需要访问同一块共享资源(比如刚提到的共享内存)时,如何避免冲突?信号量就像一个“资源计数器”或“通行证”。最常见的二元信号量(互斥锁)可以确保同一时刻只有一个进程能进入临界区。P操作(等待)尝试获取信号量,V操作(发信号)则释放信号量。

#include 
#include 
#include 
#include 
#include 

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

int main() {
    key_t key = ftok("semaphore_example.c", 65);
    int semid = semget(key, 1, 0666 | IPC_CREAT);
    if (semid == -1) {
        perror("semget");
        exit(EXIT_FAILURE);
    }

    union semun arg;
    arg.val = 1; // 初始化信号量为1
    if (semctl(semid, 0, SETVAL, arg) == -1) {
        perror("semctl");
        exit(EXIT_FAILURE);
    }

    // P操作(等待信号量)
    struct sembuf sb = {0, -1, SEM_UNDO};
    if (semop(semid, &sb, 1) == -1) {
        perror("semop");
        exit(EXIT_FAILURE);
    }
    std::cout << "Semaphore P operation completed" << std::endl;

    // V操作(释放信号量)
    sb.sem_op = 1;
    if (semop(semid, &sb, 1) == -1) {
        perror("semop");
        exit(EXIT_FAILURE);
    }
    std::cout << "Semaphore V operation completed" << std::endl;

    semctl(semid, 0, IPC_RMID); // 删除信号量
    return 0;
}

5. 套接字(Sockets)

最后登场的是功能最强大的套接字。它最初是为网络通信设计的,但同样完美适用于同一台主机上的进程间通信(通过Unix Domain Sockets)。套接字提供全双工通信,支持多种协议(如TCP的可靠流、UDP的数据报),并且是跨平台兼容性最好的IPC方式之一。如果未来你的程序有扩展到网络通信的可能,那么从一开始就使用套接字会是一个具有前瞻性的选择。

Unix Domain Sockets

这是专门用于本地IPC的套接字,它通过文件系统路径名来标识,效率比网络套接字更高,因为它避免了网络协议栈的开销。

#include 
#include 
#include 
#include 
#include 
#include 

int main() {
    struct sockaddr_un addr;
    int sockfd, connfd;
    char buffer[1024];

    sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, "/tmp/unix_socket", sizeof(addr.sun_path) - 1);
    unlink("/tmp/unix_socket"); // 删除已存在的套接字文件

    if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
        perror("bind");
        exit(EXIT_FAILURE);
    }

    if (listen(sockfd, 5) == -1) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    connfd = accept(sockfd, NULL, NULL);
    if (connfd == -1) {
        perror("accept");
        exit(EXIT_FAILURE);
    }

    read(connfd, buffer, sizeof(buffer));
    std::cout << "Received: " << buffer << std::endl;

    close(connfd);
    close(sockfd);
    return 0;
}

好了,以上就是Linux下C++常用的几种进程间通信方法。简单总结一下:管道简单直接,适合亲缘进程;命名管道打破了亲缘限制;消息队列提供了结构化的消息传递;共享内存速度最快,但需手动同步;信号量是同步的基石;而套接字则是最通用、最强大的方案。实际开发中,没有绝对的“最佳”,只有最“合适”。理解它们的原理和特性,根据你的具体场景——是要求速度、简便性,还是未来的可扩展性——来做出选择,这才是关键所在。

来源:https://www.yisu.com/ask/25595955.html
免责声明: 游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

相关攻略

Filebeat如何实现跨平台日志收集
编程语言
Filebeat如何实现跨平台日志收集

Filebeat跨平台日志收集实践指南 一 架构与关键点 面对混合IT环境,如何用一套工具搞定所有主机的日志收集?Filebeat给出了答案。它提供了覆盖Linux、Windows和macOS的安装包,这意味着,你只需要维护同一套简洁的YAML配置,就能在不同操作系统上实现统一的日志采集与输出。其轻

热心网友
05.03
Filebeat如何进行日志压缩与归档
编程语言
Filebeat如何进行日志压缩与归档

Filebeat日志压缩与归档实践 说到日志管理,很多朋友会问:Filebeat本身能搞定日志的本地压缩和长期归档吗?答案是,这事儿得分两头看。Filebeat的核心任务是采集和转发,它并不包办所有存储和归档的活儿。一个典型的实践方案是:本地用系统工具处理Filebeat自己的日志,防止磁盘爆满;远

热心网友
05.03
如何利用Filebeat进行故障排查
编程语言
如何利用Filebeat进行故障排查

Filebeat故障排查实操手册 日志采集管道卡住了?数据流突然中断?别慌,这往往是Filebeat在“报警”。作为数据管道的第一公里,它的稳定至关重要。下面这份实操指南,能帮你像老手一样,快速定位并解决大多数常见问题。 一、快速定位流程 遇到问题,按这个顺序走一遍,十有八九能找到症结所在。 确认服

热心网友
05.03
如何自定义Filebeat日志格式
编程语言
如何自定义Filebeat日志格式

Filebeat日志格式自定义指南 一 概念澄清 在动手配置之前,先得把两个容易混淆的概念理清楚: Filebeat自身运行日志:这指的是Filebeat这个“搬运工”自己工作时产生的日志,比如它有没有正常启动、遇到了什么错误。这类日志通常输出到磁盘文件或控制台,方便运维人员排错。你可以选择让它以纯

热心网友
05.03
HDFS快照如何使用
编程语言
HDFS快照如何使用

HDFS 快照使用指南 说到数据备份与恢复,HDFS快照绝对是一个高效且轻量的利器。它本质上就是文件系统在某个特定时刻的“只读照片”,专门用于应对误操作或进行历史状态对比。那么,它到底是怎么工作的?简单来说,有以下几个核心特性: 一 核心概念与适用场景 首先,HDFS快照的创建几乎是瞬间完成的,时间

热心网友
05.03

最新APP

宝宝过生日
宝宝过生日
应用辅助 04-07
台球世界
台球世界
体育竞技 04-07
解绳子
解绳子
休闲益智 04-07
骑兵冲突
骑兵冲突
棋牌策略 04-07
三国真龙传
三国真龙传
角色扮演 04-07

热门推荐

爱玛电动车开座位要钥匙吗?
电脑教程
爱玛电动车开座位要钥匙吗?

爱玛电动车座垫开启指南:无钥匙方案与应急操作全解析 想要打开爱玛电动车的座垫,其实多数情况下并不需要钥匙。具体操作方法取决于您的车型配置与锁具设计。不同型号的电动车,其座垫开启方式存在显著差异。部分中高端车型已搭载电子按键或感应式座垫锁,只需轻按车把周边、仪表盘侧方或座垫边缘的实体按钮,座垫即可自动

热心网友
05.03
小米MIX4升级澎湃2.0需要解锁Bootloader吗?
电脑教程
小米MIX4升级澎湃2.0需要解锁Bootloader吗?

小米MIX4升级澎湃OS 2 0指南:官方OTA直达,无需解锁Bootloader 对于小米MIX4用户而言,升级至全新的澎湃OS 2 0系统,过程异常简便。小米官方已将该机型纳入首批正式版全量推送计划,用户无需进行复杂的Bootloader解锁操作,即可通过无线升级(OTA)方式平滑过渡。整个升级

热心网友
05.03
爱玛电动车怎么开座位?
电脑教程
爱玛电动车怎么开座位?

爱玛电动车车座开启全攻略:三种可靠方式详解 想要打开爱玛电动车的坐垫,其实方法多样且设计周全。厂家为用户提供了三种经过国家标准认证的可靠开启方案:经典的机械钥匙旋转、便捷的遥控器一键操作,以及面向未来的智能终端控制。绝大多数车型都在坐垫左后方区域配备了独立的物理钥匙孔,确保了基础开启的可靠性。中高端

热心网友
05.03
买eth的美股上市公司有哪些?为什么选择押注 ETH 而非 BTC
web3.0
买eth的美股上市公司有哪些?为什么选择押注 ETH 而非 BTC

自2025年起,SharpLink Gaming、Bitmine Immersion Tech、Bit Digital 与 BTCS Inc 四家美股公司通过大规模购入并质押 ETH,开创了“ETH 微策略”。 自2025年以来,美股市场出现了一股引人注目的新潮流。以SharpLink Gamin

热心网友
05.03
路由器怎么安装和设置连wifi上网显示无网络?
电脑教程
路由器怎么安装和设置连wifi上网显示无网络?

路由器安装与设置的核心:三步闭环搞定网络连接 路由器安装后,Wi-Fi信号满格却显示“无网络访问”,这种情况确实令人困扰。但请先别急于断定设备损坏,绝大多数问题并非硬件故障,而是网络连接的“链路”在某个配置环节出现了中断。整个排查过程的核心,可以总结为“物理连通、参数匹配、逻辑生效”三步闭环法则。只

热心网友
05.03