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

进程和线程间的通信方式有哪些?

🌟 快来参与讨论💬,点赞👍、收藏⭐、分享📤,共创活力社区。🌟 


        在操作系统与并发编程中,进程和线程是核心执行单元,而 “通信” 是它们协同工作的关键。本文将从原理层面拆解进程间通信(IPC)与线程中通信的本质差异,再通过带详细注释的代码示例,帮助读者直观理解并实践两种通信方式。

一、核心概念:进程通信 vs 线程通信

        要理解两种通信方式的差异,首先需明确进程与线程的本质区别 ——进程拥有独立地址空间,线程共享进程地址空间,这一核心差异直接决定了它们的通信逻辑。

对比维度

进程间通信(IPC)

线程中通信

地址空间

进程独立,数据不共享

共享进程地址空间

通信核心

需借助 “中间媒介” 传递数据

可直接操作共享变量(需同步)

复杂度

较高(需内核或第三方组件支持)

较低(基于共享内存,但需处理同步问题)

典型场景

多程序协同(如浏览器与下载工具)

单程序内并发任务(如 APP 的 UI 线程与网络线程)


二、进程间通信(IPC):原理与代码示例

        由于进程地址空间独立,进程间无法直接访问彼此数据,必须通过内核提供的接口第三方共享载体实现通信。常见方式包括:管道、消息队列、共享内存、Socket 等

        在 Linux 操作系统中,进程间通信(IPC)是多进程协同工作的核心技术。本文将聚焦 Linux C++ 环境,详细讲解 管道(Pipe)消息队列(Message Queue)共享内存(Shared Memory)Socket 四种经典 IPC 方式的原理、代码实现与使用场景,每部分均附带完整注释的代码与运行结果分析,帮助读者快速上手实践。

2.1、管道(Pipe):最简单的 “父子进程通信通道”

原理剖析

管道是 Linux 中最基础的 IPC 机制,本质是 内核维护的一块环形缓冲区,仅支持 父子进程或兄弟进程 间的单向通信(半双工)。其核心特点如下:

  • 数据流向:单向(需创建两个管道实现双向通信);
  • 生命周期:随进程退出自动释放,无需手动销毁;
  • 数据传输:基于字节流,无数据边界(需约定分隔符或固定长度);
  • 内核参与:数据需从写进程拷贝到内核缓冲区,再从内核缓冲区拷贝到读进程(两次拷贝,效率中等)。

Linux C++ 代码实现(父子进程单向通信)

#include <iostream>
#include <unistd.h>   // 管道相关函数(pipe、fork)
#include <cstring>    // 字符串操作(strcpy、strlen)
#include <wait.h>     // 进程等待(waitpid)
using namespace std;int main() {// 1. 创建管道:fd[0] 为读端,fd[1] 为写端int pipe_fd[2];// pipe() 成功返回 0,失败返回 -1if (pipe(pipe_fd) == -1) {perror("pipe create failed");  // 打印错误信息(如权限不足、资源耗尽)return 1;}// 2. 创建子进程(父子进程共享管道文件描述符)pid_t pid = fork();if (pid == -1) {perror("fork failed");return 1;}// 3. 父进程:写数据到管道(pid > 0 表示当前为父进程)if (pid > 0) {// 关闭父进程的读端(单向通信场景,仅需写端)close(pipe_fd[0]);// 定义待发送的数据const char* send_data = "Hello from Parent Process (Pipe)!";// write():向管道写端写入数据,返回实际写入字节数(失败返回 -1)ssize_t write_len = write(pipe_fd[1], send_data, strlen(send_data));// 检查写入是否成功if (write_len == -1) {perror("parent write failed");close(pipe_fd[1]);  // 失败时关闭写端,避免资源泄漏return 1;}// 打印写入结果cout << "父进程:已写入 " << write_len << " 字节数据" << endl;cout << "写入内容:" << send_data << endl;// 数据写完后关闭写端(避免子进程读端一直阻塞等待)close(pipe_fd[1]);// 等待子进程读取完毕,防止父进程提前退出导致子进程异常waitpid(pid, nullptr, 0);}// 4. 子进程:从管道读数据(pid == 0 表示当前为子进程)else {// 关闭子进程的写端(单向通信场景,仅需读端)close(pipe_fd[1]);// 定义接收缓冲区(初始化清零,避免脏数据)char recv_buf[1024] = {0};// read():从管道读端读取数据,返回实际读取字节数(0 表示读端关闭,-1 表示失败)ssize_t read_len = read(pipe_fd[0], recv_buf, sizeof(recv_buf) - 1);// 处理读取结果if (read_len == -1) {perror("child read failed");close(pipe_fd[0]);  // 失败时关闭读端,避免资源泄漏return 1;} else if (read_len == 0) {cout << "子进程:管道读端已关闭(无数据可读)" << endl;close(pipe_fd[0]);return 0;}// 打印读取结果cout << "子进程:已读取 " << read_len << " 字节数据" << endl;cout << "读取内容:" << recv_buf << endl;// 读取完毕后关闭读端close(pipe_fd[0]);}return 0;
}

运行结果与解读

# 编译命令:g++ pipe_demo.cpp -o pipe_demo# 运行命令:./pipe_demo父进程:已写入 36 字节数据写入内容:Hello from Parent Process (Pipe)!子进程:已读取 36 字节数据读取内容:Hello from Parent Process (Pipe)!
  • 关键注意点:父子进程需关闭无用的管道端(如父进程关读端、子进程关写端),否则可能导致读端阻塞;
  • 适用场景:简单的父子进程数据传递(如命令行管道 ls | grep txt 就是基于管道实现)。

2.2、消息队列(Message Queue):带 “标签” 的异步通信

原理剖析

消息队列是内核维护的 消息链表,支持不同进程(无需亲缘关系)通过 “消息类型”(标签)选择性接收数据,核心特点如下:

  • 数据结构:每个消息包含 消息类型(正整数)消息数据,读进程可按类型过滤消息;
  • 生命周期:随内核存在(需手动删除,否则重启前一直存在);
  • 数据传输:一次拷贝(从写进程拷贝到内核队列,读进程从内核队列拷贝到自身地址空间);
  • 异步通信:写进程发送消息后可立即返回,读进程按需读取(无需同步等待)。

Linux C++ 代码实现(两个独立进程通信)

发送进程(msg_send.cpp)

#include <iostream>
#include <sys/msg.h>  // 消息队列相关函数(msgget、msgsnd)
#include <cstring>    // 字符串操作函数(strcpy)
#include <unistd.h>   // 系统调用基础头文件
using namespace std;// 定义消息结构体(消息队列要求必须包含 long 类型的 mtype 字段,用于标识消息类型)
struct MsgBuffer {long mtype;         // 消息类型(必须为正整数,读进程可按类型筛选消息)char mtext[1024];   // 消息数据存储区(大小可根据实际需求调整)
};int main() {// 1. 生成消息队列的唯一键值(ftok函数:将指定文件路径与自定义ID结合,生成唯一key)// 注意:路径对应的文件必须存在,自定义ID(66)取值范围为0-255,需与接收进程保持一致key_t key = ftok("/tmp/msg_queue_key", 66);if (key == -1) {  // ftok失败返回-1(如文件不存在、权限不足)perror("ftok failed");  // 打印错误原因return 1;}// 2. 创建或获取消息队列(msgget函数:根据key操作消息队列)// IPC_CREAT:若队列不存在则创建;0666:队列读写权限(所有者、组、其他用户均有读写权)int msg_id = msgget(key, IPC_CREAT | 0666);if (msg_id == -1) {  // msgget失败返回-1(如权限不足、系统资源耗尽)perror("msgget failed");return 1;}cout << "消息队列创建成功,ID:" << msg_id << endl;  // 打印队列ID,方便调试// 3. 构造消息并发送到队列(msgsnd函数:向指定队列发送消息)MsgBuffer msg;               // 定义消息结构体变量msg.mtype = 10;              // 设置消息类型为10(接收进程需按此类型接收)// 将字符串复制到消息数据区(strcpy:避免直接赋值,确保数据完整)strcpy(msg.mtext, "Hello from Send Process (Message Queue)!");// msgsnd参数说明:消息队列ID、消息地址、消息数据长度(不含mtype)、发送标志(0表示阻塞发送)if (msgsnd(msg_id, &msg, sizeof(msg.mtext), 0) == -1) {perror("msgsnd failed");  // 发送失败(如队列满、权限不足)// 失败时删除消息队列(避免内核资源泄漏,若需复用队列可注释)msgctl(msg_id, IPC_RMID, nullptr);return 1;}// 发送成功:打印消息类型与内容,确认发送结果cout << "发送成功!消息类型:" << msg.mtype << ",内容:" << msg.mtext << endl;// 4. 可选操作:不立即删除消息队列(供接收进程读取数据)// 若需单次通信,可取消注释下方代码,发送后直接删除队列(需确保接收进程已读取)// msgctl(msg_id, IPC_RMID, nullptr);// cout << "消息队列已删除" << endl;return 0;
}

接收进程(msg_recv.cpp)

#include <iostream>
#include <sys/msg.h>  // 消息队列相关函数(msgget、msgrcv)
#include <cstring>    // 内存操作函数(memset)
using namespace std;// 定义消息结构体(必须与发送进程完全一致,确保数据解析正确)
struct MsgBuffer {long mtype;         // 消息类型(接收时需匹配发送端设置的类型)char mtext[1024];   // 消息数据存储区(与发送端缓冲区大小保持一致)
};int main() {// 1. 生成与发送进程相同的键值(ftok参数需完全匹配:路径+自定义ID)// 路径对应的文件需存在,自定义ID(66)需与发送进程一致,否则无法关联同一队列key_t key = ftok("/tmp/msg_queue_key", 66);if (key == -1) {  // ftok失败(如文件不存在、权限不足)perror("ftok failed");  // 打印错误原因,便于调试return 1;}// 2. 获取已存在的消息队列(仅读取,不创建新队列)// 0666:队列读写权限(需与发送进程设置的权限一致,否则无访问权限)int msg_id = msgget(key, 0666);if (msg_id == -1) {  // 失败原因:队列未创建、权限不足、内核资源耗尽perror("msgget failed(队列不存在或权限不足)");return 1;}cout << "成功获取消息队列,ID:" << msg_id << endl;  // 打印队列ID,确认关联正确// 3. 接收消息(msgrcv:从指定队列读取符合类型的消息)MsgBuffer msg;// 初始化消息结构体(memset清零,避免缓冲区残留脏数据影响读取结果)memset(&msg, 0, sizeof(msg));// msgrcv参数说明:// msg_id:目标消息队列ID// &msg:接收消息的结构体地址// sizeof(msg.mtext):接收数据的最大长度(不含mtype字段)// 10:仅接收类型为10的消息(与发送端匹配,实现消息过滤)// 0:阻塞模式(无对应类型消息时,进程等待,直到有消息或出错)ssize_t recv_len = msgrcv(msg_id, &msg, sizeof(msg.mtext), 10, 0);// 处理接收结果if (recv_len == -1) {perror("msgrcv failed");  // 接收失败(如队列被删除、权限变更)msgctl(msg_id, IPC_RMID, nullptr);  // 清理残留队列,避免资源泄漏return 1;}// 接收成功:打印消息详情(类型、长度、内容)cout << "接收成功!消息类型:" << msg.mtype << ",长度:" << recv_len << " 字节" << endl;cout << "消息内容:" << msg.mtext << endl;// 4. 读取完毕后删除消息队列(避免内核资源长期占用,防止内存泄漏)if (msgctl(msg_id, IPC_RMID, nullptr) == -1) {perror("msgctl delete failed");  // 删除失败(如权限不足)return 1;}cout << "消息队列已删除" << endl;return 0;
}

运行结果与解读

# 第一步:创建临时文件(用于ftok生成键值)touch /tmp/msg_queue_key# 第二步:编译并运行发送进程(终端1)g++ msg_send.cpp -o msg_send./msg_send消息队列创建成功,ID:12345发送成功!消息类型:10,内容:Hello from Send Process (Message Queue)!# 第三步:编译并运行接收进程(终端2)g++ msg_recv.cpp -o msg_recv./msg_recv成功获取消息队列,ID:12345接收成功!消息类型:10,长度:1024 字节消息内容:Hello from Send Process (Message Queue)!消息队列已删除
  • 关键注意点:ftok 的路径和 ID 必须一致,否则发送 / 接收进程无法关联同一队列;
  • 适用场景:非亲缘进程的异步通信(如服务端与客户端的指令传递)。

2.3、共享内存(Shared Memory):最高效的 “内存共享”

原理剖析

共享内存是 效率最高的 IPC 方式,本质是内核在物理内存中开辟一块 “公共区域”,让多个进程将该区域映射到自身的虚拟地址空间,核心特点如下:

  • 数据传输:零拷贝(进程直接读写物理内存,无需经过内核缓冲区);
  • 同步依赖:无内置同步机制(需配合互斥锁、信号量等保证并发安全);
  • 生命周期:随内核存在(需手动删除);
  • 适用场景:高频、大数据量的进程间通信(如视频流传输、实时数据共享)。

Linux C++ 代码实现(带互斥锁同步)

#include <iostream>
#include <sys/shm.h>   // 共享内存相关函数(shmget、shmat、shmdt、shmctl)
#include <sys/ipc.h>   // 键值生成函数(ftok)
#include <sys/sem.h>   // 信号量相关函数(semget、semctl、semop)
#include <cstring>     // 字符串操作(strcpy)
#include <unistd.h>    // 进程控制(fork、sleep)
#include <wait.h>      // 进程等待(waitpid)
using namespace std;// 定义共享内存数据结构(整合同步信号量ID与实际共享数据,确保进程间同步与数据传递)
struct SharedData {int sem_id;          // 信号量ID(用于共享内存的并发访问同步)char data[1024];     // 共享数据存储区(可根据需求调整大小)
};// 信号量操作封装函数(实现P/V操作,保证共享资源的互斥访问)
// op参数:-1 表示P操作(申请资源,锁定);1 表示V操作(释放资源,解锁)
void sem_operation(int sem_id, int op) {struct sembuf sem_op;  // 信号量操作结构体sem_op.sem_num = 0;    // 信号量编号(单个信号量集合时,编号为0)sem_op.sem_op = op;    // 操作类型(P/V)sem_op.sem_flg = 0;    // 阻塞模式(无信号量可用时,进程等待)// 执行信号量操作:semop(信号量ID, 操作结构体地址, 操作数量)semop(sem_id, &sem_op, 1);
}int main() {// 1. 生成共享内存与信号量的公共键值(ftok函数:确保不同进程关联同一资源)// 路径"/tmp/shm_key"需存在,自定义ID(77)需唯一,且与关联进程保持一致key_t key = ftok("/tmp/shm_key", 77);if (key == -1) {  // ftok失败(如路径不存在、权限不足)perror("ftok failed");  // 打印错误原因,便于调试return 1;}// 2. 创建共享内存(shmget函数:申请内核共享内存区域)// 参数说明:键值、共享内存大小(结构体大小)、创建标志+权限(0666:读写权限)int shm_id = shmget(key, sizeof(SharedData), IPC_CREAT | 0666);if (shm_id == -1) {  // 失败原因:权限不足、系统资源耗尽、键值已存在但无访问权perror("shmget failed");return 1;}cout << "共享内存创建成功,ID:" << shm_id << endl;  // 打印ID,确认创建结果// 3. 将共享内存映射到当前进程的虚拟地址空间(shmat:实现进程与共享内存的关联)// 参数说明:共享内存ID、映射地址(NULL:由内核自动分配)、映射权限(0:读写)SharedData* shared_ptr = (SharedData*)shmat(shm_id, nullptr, 0);if (shared_ptr == (void*)-1) {  // 映射失败(如权限不足、共享内存已被删除)perror("shmat failed");shmctl(shm_id, IPC_RMID, nullptr);  // 清理已创建的共享内存,避免资源泄漏return 1;}// 4. 创建信号量(用于共享内存的同步,避免多进程并发读写导致数据竞争)// 参数说明:键值、信号量数量(1:单个互斥锁)、创建标志+权限(0666:读写)shared_ptr->sem_id = semget(key, 1, IPC_CREAT | 0666);if (shared_ptr->sem_id == -1) {  // 信号量创建失败perror("semget failed");shmdt(shared_ptr);             // 解除共享内存映射shmctl(shm_id, IPC_RMID, nullptr);  // 删除共享内存return 1;}// 初始化信号量值为1(互斥锁模式:初始状态为“可用”,确保同一时间仅一个进程访问)semctl(shared_ptr->sem_id, 0, SETVAL, 1);// 5. 创建子进程(父子进程共享已映射的共享内存与信号量)pid_t pid = fork();if (pid == -1) {  // 进程创建失败(如系统进程数达到上限)perror("fork failed");semctl(shared_ptr->sem_id, 0, IPC_RMID);  // 清理信号量shmdt(shared_ptr);                        // 解除映射shmctl(shm_id, IPC_RMID, nullptr);        // 删除共享内存return 1;}// 6. 父进程逻辑:向共享内存写入数据(需先通过P操作锁定信号量)if (pid > 0) {sem_operation(shared_ptr->sem_id, -1);  // P操作:申请信号量(锁定共享资源)// 向共享内存写入数据(strcpy:确保字符串完整拷贝,避免直接赋值的安全问题)strcpy(shared_ptr->data, "Hello from Parent (Shared Memory, with Semaphore)!");cout << "父进程:已写入共享内存,内容:" << shared_ptr->data << endl;sem_operation(shared_ptr->sem_id, 1);   // V操作:释放信号量(解锁共享资源)// 等待子进程读取完毕(避免父进程提前清理资源,导致子进程访问失败)waitpid(pid, nullptr, 0);// 父进程清理资源:解除映射+删除共享内存+删除信号量shmdt(shared_ptr);  // 解除当前进程与共享内存的关联shmctl(shm_id, IPC_RMID, nullptr);  // 从内核中删除共享内存(彻底释放资源)semctl(shared_ptr->sem_id, 0, IPC_RMID);  // 删除信号量cout << "父进程:资源清理完成(共享内存+信号量已删除)" << endl;}// 7. 子进程逻辑:从共享内存读取数据(同样需通过信号量同步)else {// 子进程等待片刻(确保父进程已完成数据写入,实际开发中可通过信号量精准同步)sleep(1);sem_operation(shared_ptr->sem_id, -1);  // P操作:申请信号量(锁定共享资源)// 从共享内存读取数据并打印cout << "子进程:从共享内存读取到内容:" << shared_ptr->data << endl;sem_operation(shared_ptr->sem_id, 1);   // V操作:释放信号量(解锁共享资源)// 子进程仅需解除映射(共享内存与信号量由父进程统一清理,避免重复操作)shmdt(shared_ptr);cout << "子进程:读取完成,已解除共享内存映射" << endl;}return 0;
}

三、线程中通信:原理与代码示例

        线程共享进程的地址空间,因此通信可直接通过共享变量实现,但需解决 “并发安全” 问题 —— 多个线程同时读写共享变量会导致 “数据竞争”,需通过 “同步机制”(如互斥锁、条件变量)保证原子性。

本文以 “C++11 线程库” 为例,讲解 “互斥锁 + 共享变量” 和 “条件变量” 两种通信方式。

3.1 基础通信:互斥锁 + 共享变量

原理:用std::mutex(互斥锁)保护共享变量,确保同一时间只有一个线程能读写该变量,避免数据竞争。

#include <iostream>
#include <thread>   // 线程相关类(std::thread)
#include <mutex>    // 互斥锁相关类(std::mutex、std::lock_guard)
#include <string>   // 字符串类(std::string,作为共享资源)
using namespace std;// 1. 共享资源:线程间通信的核心载体(所有线程可访问的全局变量)
// 注意:多线程读写全局变量需同步保护,否则会出现数据竞争
string shared_msg = "初始值:未修改";// 2. 互斥锁:保护共享资源的同步机制(确保同一时间仅一个线程访问共享资源)
mutex mtx;// 线程函数1:向共享变量写入数据(写操作)
void thread_write() {// 加锁:std::lock_guard 是 RAII 风格锁,构造时自动加锁,作用域结束时自动解锁// 避免手动加锁后忘记解锁导致死锁lock_guard<mutex> lock(mtx);// 安全修改共享变量:此时当前线程独占共享资源,其他线程需等待解锁shared_msg = "线程1已修改:Hello Thread Communication!";cout << "线程1(写):" << shared_msg << endl;
}// 线程函数2:从共享变量读取数据(读操作)
void thread_read() {// 加锁:即使是读操作,也需加锁避免与写操作并发(防止“脏读”)lock_guard<mutex> lock(mtx);// 安全读取共享变量:确保读取时无其他线程修改数据cout << "线程2(读):" << shared_msg << endl;
}int main() {// 创建两个线程:分别绑定写操作和读操作的线程函数thread t1(thread_write);  // t1 执行写共享变量逻辑thread t2(thread_read);   // t2 执行读共享变量逻辑// 等待线程执行完毕:std::thread::join() 会阻塞主线程,直到子线程完成// 若不调用 join(),主线程提前退出会导致子线程被强制终止(资源异常)t1.join();t2.join();return 0;
}

运行结果(无数据竞争,结果稳定):

线程1(写):线程1已修改:Hello Thread Communication!线程2(读):线程1已修改:Hello Thread Communication!

3.2 进阶通信:条件变量(线程间通知)

原理:当线程需要 “等待某个条件满足” 时(如共享变量达到特定值),用std::condition_variable实现 “等待 - 通知” 机制,避免线程空循环轮询(节省 CPU 资源)。

#include <iostream>
#include <thread>           // 线程类(std::thread)
#include <mutex>            // 互斥锁(std::mutex)、RAII锁(std::lock_guard)
#include <condition_variable> // 条件变量(std::condition_variable)
#include <queue>            // 队列容器(std::queue,作为共享缓冲区)
#include <chrono>           // 时间相关(std::chrono::seconds,模拟生产耗时)
using namespace std;// 1. 共享资源:生产者与消费者的通信载体(队列缓冲区)
// 队列存储生产的数据,多线程访问需通过互斥锁保护
queue<int> shared_queue;// 2. 同步机制:确保共享资源的安全访问与线程间通知
mutex mtx;                      // 互斥锁:保护队列与状态变量的并发读写
condition_variable cv;          // 条件变量:实现线程间“等待-通知”(避免空轮询)
bool is_finished = false;       // 状态标记:标记生产者是否完成所有生产任务// 线程函数1:生产者(向共享队列添加数据)
void producer() {// 生产5个数据(模拟批量生产过程)for (int i = 1; i <= 5; ++i) {// 加锁:仅在操作共享队列时加锁,减少锁占用时间(提高并发效率){lock_guard<mutex> lock(mtx);  // RAII锁:作用域结束自动解锁shared_queue.push(i);         // 生产数据:将数据加入共享队列cout << "生产者:添加数据 " << i << ",队列大小:" << shared_queue.size() << endl;}// 通知消费者:队列已有数据,可唤醒等待的消费者进行消费// notify_one():仅唤醒一个等待该条件变量的线程(避免惊群效应)cv.notify_one();// 模拟生产耗时(让消费者有机会进入等待状态,体现条件变量作用)this_thread::sleep_for(chrono::seconds(1));}// 生产完毕:标记状态并通知消费者(避免消费者一直等待){lock_guard<mutex> lock(mtx);is_finished = true;  // 更新状态:告知消费者“后续无新数据”}cv.notify_one();  // 唤醒可能等待的消费者,让其检查退出条件
}// 线程函数2:消费者(从共享队列取出数据)
void consumer() {// 循环消费:直到“生产完毕且队列空”才退出while (true) {// 加锁:条件变量需配合std::unique_lock(支持手动解锁,满足wait()的解锁需求)unique_lock<mutex> lock(mtx);// 等待条件:当“队列空且生产未完毕”时,消费者进入等待状态(释放锁)// wait()逻辑:1. 初始检查条件,满足则继续;2. 不满足则释放锁并阻塞;3. 被通知后重新加锁并检查条件cv.wait(lock, [](){ return !shared_queue.empty() || is_finished; });// 退出条件:生产已完毕 + 队列中无剩余数据(确保消费完所有数据)if (is_finished && shared_queue.empty()) {cout << "消费者:生产完毕,退出" << endl;break;}// 消费数据:从队列头部取出数据并删除int data = shared_queue.front();shared_queue.pop();cout << "消费者:取出数据 " << data << ",队列大小:" << shared_queue.size() << endl;}
}int main() {// 创建生产者与消费者线程thread t_producer(producer);  // 生产者线程:执行producer()thread t_consumer(consumer);  // 消费者线程:执行consumer()// 等待线程执行完毕:主线程阻塞,直到子线程完成所有任务t_producer.join();t_consumer.join();return 0;
}

运行结果(生产者通知后消费者才消费,无空轮询):

生产者:添加数据 1,队列大小:1消费者:取出数据 1,队列大小:0生产者:添加数据 2,队列大小:1消费者:取出数据 2,队列大小:0生产者:添加数据 3,队列大小:1消费者:取出数据 3,队列大小:0生产者:添加数据 4,队列大小:1消费者:取出数据 4,队列大小:0生产者:添加数据 5,队列大小:1消费者:取出数据 5,队列大小:0消费者:生产完毕,退出

四、总结:核心差异与选择建议

维度

进程间通信(IPC)

线程中通信

数据共享

无共享,需中间载体

共享进程内存,直接访问变量

同步需求

部分方式需同步(如共享内存)

必须同步(互斥锁 / 条件变量)

效率

较低(多为内核态拷贝)

较高(用户态操作,无额外拷贝)

适用场景

跨程序协同(如多服务通信)

单程序内并发(如任务拆分)

  • 选择建议
  • 若需多程序协作(如浏览器与插件),优先选IPC(共享内存 / Socket);
  • 若需单程序内高效并发(如 APP 后台任务),优先选线程通信(互斥锁 / 条件变量);
  • 线程通信需警惕 “死锁”(如多锁顺序不一致),IPC 需注意 “资源泄漏”(如未删除共享内存)。

如果在学习过程中有任何疑问或建议,欢迎随时交流分享哦😉! 👉【A Charmer】

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

相关文章:

  • 铁威马内置wordpress目录长春网络优化哪个公司在做
  • 哪个网站建设公司好济南网站建设公司熊掌号
  • 企业建站系统免费白云外贸型网站建设
  • 天津个人专业做网站wordpress分享有礼
  • 安新网站建设网站服务器到期为什么要网站备案
  • 哈希和加密
  • 济南seo网站排名优化工具公司简介宣传文案
  • 正规的网站优化推广公司广告牌模板图片
  • 那家公司做网站比较好微信公众号文章 转wordpress
  • 龙岗网站设计资讯怎么做素材设计网站
  • FastAPI 深度剖析:从异步原理到高级应用
  • AIGC(生成式AI)试用 37 -- 辅助测试 Browser-use, Playwright
  • 做视频网站收入wordpress与discuz整合
  • oracle 网站开发箱包商城网站建设
  • [crackme]018-crackme_0006
  • 滨海专业做网站wordpress博客分页
  • 如何做衣服销售网站淄博网站制作制作
  • 东台建设局网站公司信息查询网
  • 建站套餐和定制网站的区别2013电子商务网站建设考试试卷
  • 中山币做网站公司网站的建设不包括什么
  • CSP 复赛入门组高频算法:典型例题、代码模板与实战题号
  • 做网站需要哪些准备工作心得体会简短的
  • 基础建设文本网站阿里云1M做网站
  • 江苏建设工程信息网站网站的设计页面
  • 网站建设工作基本流程做二手网站赚钱不
  • 嵌入式学习笔记5.定时器TIM
  • 博达高校网站群建设教程家在临深业主论坛家在深圳
  • 两学一做网站网站网站开发前端库
  • 模型轻量化三大核心技术之:蒸馏
  • 备案关闭网站建设影响淮南最新通告今天