C++ 進(jìn)程間通信IPC的實(shí)現(xiàn)示例
進(jìn)程間通信(Inter-Process Communication, IPC)是操作系統(tǒng)提供的允許不同進(jìn)程間交換數(shù)據(jù)和同步行為的機(jī)制。C++作為系統(tǒng)級(jí)編程語(yǔ)言,支持多種IPC方式。本文將詳細(xì)介紹C++中常用的進(jìn)程間通信技術(shù)。
1. 管道(Pipe)
1.1 匿名管道
匿名管道是Unix-like系統(tǒng)中最基礎(chǔ)的IPC方式,具有以下特點(diǎn):
- 單向通信,半雙工
- 只能用于有親緣關(guān)系的進(jìn)程間通信
- 基于字節(jié)流
#include <unistd.h>
#include <iostream>
int main() {
int fd[2];
pipe(fd); // 創(chuàng)建管道
if (fork() == 0) { // 子進(jìn)程
close(fd[0]); // 關(guān)閉讀端
write(fd[1], "Hello", 6);
close(fd[1]);
} else { // 父進(jìn)程
close(fd[1]); // 關(guān)閉寫端
char buf[20];
read(fd[0], buf, sizeof(buf));
std::cout << "Received: " << buf << std::endl;
close(fd[0]);
}
return 0;
}
1.2 命名管道(FIFO)
命名管道克服了匿名管道的限制:
- 有文件名與之關(guān)聯(lián)
- 可用于無親緣關(guān)系的進(jìn)程間通信
- 通過文件系統(tǒng)實(shí)現(xiàn)
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
// 進(jìn)程1: 創(chuàng)建并寫入FIFO
mkfifo("/tmp/myfifo", 0666);
int fd = open("/tmp/myfifo", O_WRONLY);
write(fd, "Hello FIFO", 10);
close(fd);
// 進(jìn)程2: 讀取FIFO
int fd = open("/tmp/myfifo", O_RDONLY);
char buf[20];
read(fd, buf, sizeof(buf));
close(fd);
2. 消息隊(duì)列(Message Queue)
消息隊(duì)列提供了一種結(jié)構(gòu)化數(shù)據(jù)交換方式:
- 消息被賦予類型,可按類型接收
- 獨(dú)立于發(fā)送和接收進(jìn)程存在
- 克服了管道無格式字節(jié)流的限制
#include <sys/ipc.h>
#include <sys/msg.h>
#include <iostream>
struct message {
long mtype;
char mtext[100];
};
int main() {
key_t key = ftok("progfile", 65);
int msgid = msgget(key, 0666 | IPC_CREAT);
message msg;
msg.mtype = 1;
sprintf(msg.mtext, "Hello Message Queue");
// 發(fā)送消息
msgsnd(msgid, &msg, sizeof(msg.mtext), 0);
// 接收消息
msgrcv(msgid, &msg, sizeof(msg.mtext), 1, 0);
std::cout << "Received: " << msg.mtext << std::endl;
// 刪除消息隊(duì)列
msgctl(msgid, IPC_RMID, NULL);
return 0;
}
3. 共享內(nèi)存(Shared Memory)
共享內(nèi)存是最快的IPC方式:
- 多個(gè)進(jìn)程訪問同一塊物理內(nèi)存
- 不涉及數(shù)據(jù)復(fù)制
- 需要同步機(jī)制配合使用
#include <sys/ipc.h>
#include <sys/shm.h>
#include <iostream>
int main() {
key_t key = ftok("shmfile", 65);
int shmid = shmget(key, 1024, 0666 | IPC_CREAT);
// 附加共享內(nèi)存
char *str = (char*)shmat(shmid, (void*)0, 0);
std::cout << "Write Data: ";
std::cin.getline(str, 1024);
std::cout << "Data in memory: " << str << std::endl;
// 分離共享內(nèi)存
shmdt(str);
// 刪除共享內(nèi)存
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
4. 信號(hào)量(Semaphore)
信號(hào)量用于進(jìn)程間同步:
- 控制對(duì)共享資源的訪問
- 避免競(jìng)爭(zhēng)條件
- 可以是二進(jìn)制或計(jì)數(shù)信號(hào)量
#include <sys/ipc.h>
#include <sys/sem.h>
#include <iostream>
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);
semun su;
su.val = 1; // 初始值
semctl(semid, 0, SETVAL, su);
sembuf sb = {0, -1, 0}; // P操作
semop(semid, &sb, 1);
// 臨界區(qū)代碼
std::cout << "In critical section" << std::endl;
sb.sem_op = 1; // V操作
semop(semid, &sb, 1);
return 0;
}
5. 套接字(Socket)
套接字是最通用的IPC方式:
- 可用于同一主機(jī)或不同主機(jī)上的進(jìn)程通信
- 支持多種協(xié)議(TCP/UDP)
- 全雙工通信
// 服務(wù)器端
#include <sys/socket.h>
#include <netinet/in.h>
#include <iostream>
int main() {
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);
bind(server_fd, (struct sockaddr*)&address, sizeof(address));
listen(server_fd, 3);
int new_socket = accept(server_fd, NULL, NULL);
char buffer[1024] = {0};
read(new_socket, buffer, 1024);
std::cout << "Message: " << buffer << std::endl;
close(new_socket);
close(server_fd);
return 0;
}
// 客戶端
#include <sys/socket.h>
#include <arpa/inet.h>
int main() {
int sock = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);
connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
send(sock, "Hello Socket", 12, 0);
close(sock);
return 0;
}
6. 信號(hào)(Signal)
信號(hào)是異步通知機(jī)制:
- 用于通知進(jìn)程發(fā)生了某種事件
- 有限種類的預(yù)定義信號(hào)
- 不能傳遞復(fù)雜數(shù)據(jù)
#include <signal.h>
#include <unistd.h>
#include <iostream>
void handler(int sig) {
std::cout << "Received signal: " << sig << std::endl;
}
int main() {
signal(SIGINT, handler); // 注冊(cè)信號(hào)處理函數(shù)
std::cout << "Waiting for signal..." << std::endl;
pause(); // 等待信號(hào)
return 0;
}
7. 文件鎖(File Locking)
文件鎖用于協(xié)調(diào)對(duì)文件的訪問:
- 避免多個(gè)進(jìn)程同時(shí)修改同一文件
- 可以是建議鎖或強(qiáng)制鎖
- 支持共享鎖和排他鎖
#include <sys/file.h>
#include <fcntl.h>
#include <unistd.h>
#include <iostream>
int main() {
int fd = open("testfile.txt", O_RDWR | O_CREAT, 0666);
// 獲取排他鎖
if (flock(fd, LOCK_EX) == -1) {
perror("flock");
return 1;
}
// 臨界區(qū)操作
write(fd, "Hello File Lock", 15);
// 釋放鎖
flock(fd, LOCK_UN);
close(fd);
return 0;
}
8. Windows特有的IPC機(jī)制
8.1 郵槽(Mailslot)
- 單向通信
- 基于消息
- 主要用于廣播消息
// 服務(wù)器端
HANDLE hMailslot = CreateMailslot(
"\\\\.\\mailslot\\sample_mailslot",
0,
MAILSLOT_WAIT_FOREVER,
NULL);
// 客戶端
HANDLE hFile = CreateFile(
"\\\\.\\mailslot\\sample_mailslot",
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
8.2 內(nèi)存映射文件(Memory-Mapped File)
類似于共享內(nèi)存,但有文件支持
// 創(chuàng)建者
HANDLE hFile = CreateFile("shared.dat", ...);
HANDLE hMap = CreateFileMapping(hFile, ...);
LPVOID pBuf = MapViewOfFile(hMap, ...);
// 訪問者
HANDLE hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "SharedMemory");
LPVOID pBuf = MapViewOfFile(hMap, ...);
9. 高級(jí)IPC技術(shù)
9.1 D-Bus
- 高級(jí)消息總線系統(tǒng)
- 主要用于桌面環(huán)境中的進(jìn)程通信
- 支持遠(yuǎn)程對(duì)象調(diào)用
#include <dbus/dbus.h>
DBusConnection* conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
dbus_bus_request_name(conn, "com.example.Service", 0, NULL);
DBusMessage* msg = dbus_message_new_signal(
"/com/example/Object",
"com.example.Interface",
"SignalName");
dbus_connection_send(conn, msg, NULL);
dbus_message_unref(msg);
9.2 CORBA
- 公共對(duì)象請(qǐng)求代理體系結(jié)構(gòu)
- 支持跨語(yǔ)言、跨平臺(tái)的分布式對(duì)象通信
- 使用IDL定義接口
// IDL定義
interface Hello {
string sayHello();
};
// C++實(shí)現(xiàn)
class HelloImpl : public virtual POA_Hello {
public:
char* sayHello() {
return CORBA::string_dup("Hello CORBA!");
}
};
10. IPC方式比較與選擇指南
| IPC方式 | 適用場(chǎng)景 | 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|---|---|
| 管道 | 父子進(jìn)程間簡(jiǎn)單通信 | 簡(jiǎn)單易用 | 單向通信,只能親緣進(jìn)程 |
| 命名管道 | 任意進(jìn)程間簡(jiǎn)單通信 | 可用于無親緣進(jìn)程 | 仍然是單向通信 |
| 消息隊(duì)列 | 結(jié)構(gòu)化消息傳遞 | 消息有類型,可非阻塞讀取 | 系統(tǒng)范圍限制(隊(duì)列數(shù)量、大小) |
| 共享內(nèi)存 | 高性能大數(shù)據(jù)量通信 | 最快IPC方式 | 需要額外同步機(jī)制 |
| 信號(hào)量 | 進(jìn)程同步 | 有效解決競(jìng)爭(zhēng)條件 | 不直接傳輸數(shù)據(jù) |
| 套接字 | 網(wǎng)絡(luò)或本地進(jìn)程通信 | 最通用,支持不同主機(jī) | 開銷較大 |
| 信號(hào) | 異步事件通知 | 簡(jiǎn)單通知機(jī)制 | 信息量有限 |
| 文件鎖 | 文件訪問協(xié)調(diào) | 簡(jiǎn)單文件同步 | 粒度較粗 |
| D-Bus | 桌面環(huán)境進(jìn)程通信 | 高級(jí)抽象,支持遠(yuǎn)程調(diào)用 | 復(fù)雜度高 |
| CORBA | 分布式系統(tǒng),跨語(yǔ)言通信 | 語(yǔ)言中立,支持復(fù)雜對(duì)象 | 重量級(jí),學(xué)習(xí)曲線陡峭 |
選擇建議:
- 簡(jiǎn)單通信:考慮管道或命名管道
- 結(jié)構(gòu)化消息:使用消息隊(duì)列
- 高性能數(shù)據(jù)共享:共享內(nèi)存+信號(hào)量
- 網(wǎng)絡(luò)或通用通信:套接字
- 桌面應(yīng)用:D-Bus
- 企業(yè)級(jí)分布式系統(tǒng):CORBA或類似技術(shù)
11. 安全考慮
- 權(quán)限控制:設(shè)置適當(dāng)?shù)奈募?quán)限和IPC對(duì)象權(quán)限
- 輸入驗(yàn)證:驗(yàn)證接收到的所有數(shù)據(jù)
- 資源限制:防止IPC資源耗盡攻擊
- 加密敏感數(shù)據(jù):特別是通過網(wǎng)絡(luò)或共享內(nèi)存?zhèn)鬏敃r(shí)
- 最小特權(quán)原則:只授予必要的訪問權(quán)限
12. 性能優(yōu)化技巧
- 減少數(shù)據(jù)復(fù)制:優(yōu)先考慮共享內(nèi)存
- 批量處理:合并小消息為大批次
- 異步通信:避免阻塞等待
- 適當(dāng)緩沖區(qū)大小:避免頻繁重新分配
- 選擇輕量級(jí)協(xié)議:如UDP而非TCP(如果適用)
13. 跨平臺(tái)考慮
- 抽象層:為不同平臺(tái)實(shí)現(xiàn)統(tǒng)一的IPC接口
- 條件編譯:使用預(yù)處理器指令處理平臺(tái)差異
- 第三方庫(kù):如Boost.Interprocess提供跨平臺(tái)IPC
- 測(cè)試:在所有目標(biāo)平臺(tái)上充分測(cè)試
14. 實(shí)際應(yīng)用案例
14.1 多進(jìn)程日志系統(tǒng)
- 使用共享內(nèi)存存儲(chǔ)日志緩沖區(qū)
- 信號(hào)量控制并發(fā)訪問
- 日志寫入進(jìn)程和日志讀取/處理進(jìn)程分離
14.2 分布式計(jì)算
- 主進(jìn)程通過消息隊(duì)列分發(fā)任務(wù)
- 工作進(jìn)程通過共享內(nèi)存返回結(jié)果
- 信號(hào)量同步任務(wù)狀態(tài)
14.3 微服務(wù)架構(gòu)
- 使用D-Bus或gRPC進(jìn)行服務(wù)間通信
- 共享內(nèi)存用于高性能數(shù)據(jù)交換
- 信號(hào)量協(xié)調(diào)資源訪問
15. 總結(jié)
C++提供了豐富的進(jìn)程間通信機(jī)制,從簡(jiǎn)單的管道到復(fù)雜的分布式對(duì)象系統(tǒng)。選擇適當(dāng)?shù)腎PC技術(shù)需要考慮以下因素:
- 通信模式:?jiǎn)蜗?雙向,同步/異步
- 數(shù)據(jù)量:小消息還是大數(shù)據(jù)塊
- 性能要求:延遲和吞吐量需求
- 進(jìn)程關(guān)系:是否有親緣關(guān)系
- 平臺(tái)限制:目標(biāo)操作系統(tǒng)和環(huán)境
理解各種IPC技術(shù)的優(yōu)缺點(diǎn)和適用場(chǎng)景,可以幫助開發(fā)者構(gòu)建高效、可靠的進(jìn)程間通信系統(tǒng)。在實(shí)際項(xiàng)目中,往往需要組合使用多種IPC技術(shù)來滿足不同的通信需求。# C++ 進(jìn)程間通信(IPC)方式全面解析
到此這篇關(guān)于C++ 進(jìn)程間通信IPC的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)C++ 進(jìn)程間通信IPC內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++ std::condition_variable 條件變量用法解析
condition_variable(條件變量)是 C++11 中提供的一種多線程同步機(jī)制,它允許一個(gè)或多個(gè)線程等待另一個(gè)線程發(fā)出通知,以便能夠有效地進(jìn)行線程同步,這篇文章主要介紹了C++ std::condition_variable 條件變量用法,需要的朋友可以參考下2023-09-09
關(guān)于C語(yǔ)言動(dòng)態(tài)內(nèi)存管理介紹
大家好,本篇文章主要講的是關(guān)于C語(yǔ)言動(dòng)態(tài)內(nèi)存管理介紹,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下2022-01-01
淺析c#中如何在form的webbrowser控件中獲得鼠標(biāo)坐標(biāo)
以下是對(duì)c#中如何在form的webbrowser控件中獲得鼠標(biāo)坐標(biāo)的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以參考下2013-07-07
VC通過托盤圖標(biāo)得到該所屬進(jìn)程的實(shí)現(xiàn)代碼
這篇文章主要介紹了VC通過托盤圖標(biāo)得到該所屬進(jìn)程的實(shí)現(xiàn)代碼,為了方便大家使用特將多個(gè)代碼分享給大家,需要的朋友可以參考下2021-10-10
C/C++標(biāo)準(zhǔn)庫(kù)之轉(zhuǎn)換UTC時(shí)間到local本地時(shí)間詳解
最近遇到一個(gè)問題:數(shù)據(jù)庫(kù)中存放的時(shí)間為UTC時(shí)間,但是現(xiàn)在要求都出來顯示的時(shí)間為本地時(shí)間,所以就用C++實(shí)現(xiàn)了,下面這篇文章主要給大家介紹了關(guān)于C/C++標(biāo)準(zhǔn)庫(kù)之轉(zhuǎn)換UTC時(shí)間到local本地時(shí)間的方法,還有C++中獲取UTC時(shí)間精確到微秒的實(shí)現(xiàn)代碼,需要的朋友可以參考下。2017-11-11
C語(yǔ)言之實(shí)現(xiàn)棧的基礎(chǔ)創(chuàng)建
這篇文章主要介紹了C語(yǔ)言之實(shí)現(xiàn)棧的基礎(chǔ)創(chuàng)建,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
Linux系統(tǒng)下如何使用C++解析json文件詳解
JSON(JavaScript Object Notation, JS 對(duì)象簡(jiǎn)譜) 是一種輕量級(jí)的數(shù)據(jù)交換格式。下面這篇文章主要給大家介紹了關(guān)于Linux系統(tǒng)下如何使用C++解析json文件的相關(guān)資料,需要的朋友可以參考下2021-06-06

