如何让两个子进程从同一匿名管道读取同一个写入的数字?
解决方法:让两个子进程读取同一管道写入的数字
匿名管道的核心限制是单向单消费:管道缓冲区中的数据会被第一个成功读取的进程取走,剩余进程无法再获取该数据。你之前尝试的GetStdHandle(STD_INPUT_HANDLE)和cin.peek失败,本质是因为两个子进程共享了同一个管道读端,数据被第一个进程读取后就从缓冲区消失了。
以下是三种可行的解决方案:
1. 创建两个独立的匿名管道
为每个子进程分配一个专属的匿名管道,父进程向每个管道写入相同的数字。这样每个子进程都能从自己的管道读端获取完整数据。
父进程代码示例:
#include <windows.h> #include <iostream> int main() { SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; HANDLE hRead1, hWrite1, hRead2, hWrite2; // 创建两个独立的管道 CreatePipe(&hRead1, &hWrite1, &sa, 0); CreatePipe(&hRead2, &hWrite2, &sa, 0); // 启动子进程1,绑定第一个管道的读端作为标准输入 STARTUPINFO si1 = { sizeof(STARTUPINFO) }; si1.hStdInput = hRead1; si1.dwFlags = STARTF_USESTDHANDLES; PROCESS_INFORMATION pi1; CreateProcess(NULL, L"ChildProcess.exe", NULL, NULL, TRUE, 0, NULL, NULL, &si1, &pi1); // 启动子进程2,绑定第二个管道的读端作为标准输入 STARTUPINFO si2 = { sizeof(STARTUPINFO) }; si2.hStdInput = hRead2; si2.dwFlags = STARTF_USESTDHANDLES; PROCESS_INFORMATION pi2; CreateProcess(NULL, L"ChildProcess.exe", NULL, NULL, TRUE, 0, NULL, NULL, &si2, &pi2); // 向两个管道写入相同数字 int targetNum = 456; DWORD bytesWritten; WriteFile(hWrite1, &targetNum, sizeof(targetNum), &bytesWritten, NULL); WriteFile(hWrite2, &targetNum, sizeof(targetNum), &bytesWritten, NULL); // 清理句柄 CloseHandle(hRead1); CloseHandle(hRead2); CloseHandle(hWrite1); CloseHandle(hWrite2); CloseHandle(pi1.hProcess); CloseHandle(pi1.hThread); CloseHandle(pi2.hProcess); CloseHandle(pi2.hThread); return 0; }
子进程代码示例:
#include <windows.h> #include <iostream> int main() { int num; DWORD bytesRead; HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); ReadFile(hStdin, &num, sizeof(num), &bytesRead, NULL); std::cout << "子进程读取到数字:" << num << std::endl; return 0; }
2. 使用命名管道(Named Pipe)
命名管道支持多客户端连接,父进程作为服务器创建管道,两个子进程作为客户端分别连接,父进程向每个连接的客户端写入数据。
父进程代码片段:
#include <windows.h> int main() { // 创建支持多实例的命名管道 HANDLE hPipe = CreateNamedPipe( L"\\\\.\\pipe\\SharedNumberPipe", PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 0, 0, 5000, NULL ); int targetNum = 789; DWORD bytesWritten; // 等待第一个子进程连接并写入数据 ConnectNamedPipe(hPipe, NULL); WriteFile(hPipe, &targetNum, sizeof(targetNum), &bytesWritten, NULL); CloseHandle(hPipe); // 重新创建管道实例,等待第二个子进程连接 hPipe = CreateNamedPipe( L"\\\\.\\pipe\\SharedNumberPipe", PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 0, 0, 5000, NULL ); ConnectNamedPipe(hPipe, NULL); WriteFile(hPipe, &targetNum, sizeof(targetNum), &bytesWritten, NULL); CloseHandle(hPipe); return 0; }
子进程代码片段:
#include <windows.h> #include <iostream> int main() { HANDLE hPipe = CreateFile( L"\\\\.\\pipe\\SharedNumberPipe", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL ); int num; DWORD bytesRead; ReadFile(hPipe, &num, sizeof(num), &bytesRead, NULL); std::cout << "子进程读取到数字:" << num << std::endl; CloseHandle(hPipe); return 0; }
3. 使用共享内存
父进程创建一块共享内存区域写入数字,两个子进程通过名称打开该共享内存并读取数据,这种方式更适合频繁共享数据的场景。
父进程代码片段:
#include <windows.h> int main() { // 创建共享内存 HANDLE hFileMap = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(int), L"SharedNumMemory" ); // 映射到进程地址空间并写入数字 int* pNum = (int*)MapViewOfFile(hFileMap, FILE_MAP_WRITE, 0, 0, sizeof(int)); *pNum = 101; // 等待子进程读取(可根据实际需求调整等待逻辑) system("pause"); // 清理 UnmapViewOfFile(pNum); CloseHandle(hFileMap); return 0; }
子进程代码片段:
#include <windows.h> #include <iostream> int main() { // 打开共享内存 HANDLE hFileMap = OpenFileMapping(FILE_MAP_READ, FALSE, L"SharedNumMemory"); // 映射到进程地址空间并读取数字 int* pNum = (int*)MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, sizeof(int)); std::cout << "子进程读取到数字:" << *pNum << std::endl; // 清理 UnmapViewOfFile(pNum); CloseHandle(hFileMap); return 0; }
内容的提问来源于stack exchange,提问作者Влад Солодов
相关产品推荐
相关产品推荐

