C++ 使用ReadFile和WriteFile时发生死锁

C++ 使用ReadFile和WriteFile时发生死锁,c++,winapi,C++,Winapi,我正在做一个学校项目,我试图在一个孩子的标准过程中展示在家长标准文本中写的东西;反之亦然,也就是说,显示在父标准输出上的子进程StdIn上写了什么,但是我在ReadFile和WriteFile操作中遇到了死锁 从我在本主题研究期间收集到的信息来看,这是使用同步管道时的一个常见问题 管道上的读写操作是否应通过事件同步? 你有其他建议吗? 如有任何建议,将不胜感激,提前感谢 Parent.cpp #include <windows.h> #include <iostr

我正在做一个学校项目,我试图在一个孩子的标准过程中展示在家长标准文本中写的东西;反之亦然,也就是说,显示在父标准输出上的子进程StdIn上写了什么,但是我在ReadFile和WriteFile操作中遇到了死锁

从我在本主题研究期间收集到的信息来看,这是使用同步管道时的一个常见问题

管道上的读写操作是否应通过事件同步? 你有其他建议吗? 如有任何建议,将不胜感激,提前感谢

Parent.cpp

   #include <windows.h>
   #include <iostream>
   #include <stdio.h>

   //read handle pipe1
   HANDLE r1 = NULL;

   //write handle pip1
   HANDLE w1 = NULL;

   //read handle pipe2
   HANDLE r2 = NULL;

   //write handle for pipe2
   HANDLE w2 = NULL;

   #define BUFSIZE 4096

   void CreateChildProcess() {
       TCHAR applicationName[] = TEXT("Child");
       PROCESS_INFORMATION pi;
       STARTUPINFO si;
       BOOL success = FALSE;

       ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
       ZeroMemory(&si, sizeof(STARTUPINFO));

       si.cb = sizeof(STARTUPINFO);
       si.hStdError = w1;
       si.hStdOutput = w1;
       si.hStdInput = r2;
       si.dwFlags |= STARTF_USESTDHANDLES;


       success = CreateProcess(NULL, applicationName, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);

       if (!success) {
           printf("Error creating child process \n");
       }
       else {

           printf("Child process successfuly created \n");
           CloseHandle(pi.hProcess);
           CloseHandle(pi.hThread);
       }
   }
   void WriteToPipe() {
       DWORD read, written;
       CHAR chBuf[BUFSIZE];
       BOOL success = FALSE;

       HANDLE pStdIn = GetStdHandle(STD_INPUT_HANDLE);

       for (;;)
       {
           success = ReadFile(pStdIn, chBuf, BUFSIZE, &read, NULL);
           if (!success || read == 0) break;

           success = WriteFile(w2, chBuf, read, &written, NULL);
           if (!success) break;
       }
   }

   void ReadFromPipe() {
       DWORD read, written;
       CHAR chBuf[BUFSIZE];
       BOOL success = FALSE;

       HANDLE pStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

       for (;;)
       {
           success = ReadFile(r1, chBuf, BUFSIZE, &read, NULL);
           if (!success || read == 0) break;

           success = WriteFile(pStdOut, chBuf, read, &written, NULL);
           if (!success) break;
       }
   }

   int main()
   {

       DWORD dRead, dWritten;
       CHAR chBuf[BUFSIZE];
       BOOL bSuccess = FALSE;

       SECURITY_ATTRIBUTES secAttr;
       secAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
       secAttr.bInheritHandle = TRUE;
       secAttr.lpSecurityDescriptor = NULL;

       printf("Creating first pipe\n");
       if (!CreatePipe(&r1, &w1, &secAttr, 0)) {
           printf("\nError creating first pipe\n");
       }
       printf("Creating second pipe\n");
       if (!CreatePipe(&r2, &w2, &secAttr, 0)) {
           printf("Error creating second pipe \n");
       }


       if (!SetHandleInformation(r1, HANDLE_FLAG_INHERIT, 0)) {
           printf("r1 SetHandleInformation \n");
       }
       if (!SetHandleInformation(w2, HANDLE_FLAG_INHERIT, 0)) {
           printf("w2 SetHandleInformation \n");
       }


       printf("\nCreating child process..... \n");
       CreateChildProcess();

       WriteToPipe();
       ReadFromPipe();

       return 0;
   }

Child.cpp

   #include <windows.h>
   #include <stdio.h>
   #include "pch.h"

   #define BUFSIZE 4096

   int main()
   {
       DWORD dRead, dWritten;
       CHAR chBuf[BUFSIZE];
       BOOL success = FALSE;
       HANDLE stdIn = GetStdHandle(STD_INPUT_HANDLE);
       HANDLE stdOut = GetStdHandle(STD_OUTPUT_HANDLE);


       if (stdIn == INVALID_HANDLE_VALUE || stdOut == INVALID_HANDLE_VALUE) {
           ExitProcess(1);
       }

       for (;;) {
           success = ReadFile(stdIn, chBuf, BUFSIZE, &dRead, NULL);
           if (!success || dRead == 0) break;
success = WriteFile(stdOut, chBuf, dRead, &dWritten, NULL);
           if (!success) break;
       }

       return 0;
   }
Parent.cpp
#包括
#包括
#包括
//读取句柄管道1
句柄r1=NULL;
//写入句柄pip1
句柄w1=NULL;
//读取句柄管道2
句柄r2=NULL;
//pipe2的写入句柄
句柄w2=NULL;
#定义BUFSIZE 4096
void CreateChildProcess(){
TCHAR applicationName[]=文本(“子项”);
处理信息;
STARTUPINFO si;
布尔成功=假;
零内存(&pi,sizeof(进程信息));
零内存(&si,sizeof(STARTUPINFO));
si.cb=sizeof(STARTUPINFO);
si.hStdError=w1;
si.hst输出=w1;
si.hStdInput=r2;
si.dwFlags |=STARTF_USESTDHANDLES;
success=CreateProcess(NULL,applicationName,NULL,NULL,TRUE,CREATE\u NEW\u控制台,NULL,NULL,&si,&pi);
如果(!成功){
printf(“创建子进程时出错”);
}
否则{
printf(“成功创建子进程\n”);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
void WriteToPipe(){
德沃德读,写;
CHAR chBuf[BUFSIZE];
布尔成功=假;
句柄pStdIn=GetStdHandle(标准输入句柄);
对于(;;)
{
success=ReadFile(pStdIn、chBuf、BUFSIZE和read,NULL);
如果(!success | | read==0)中断;
success=WriteFile(w2,chBuf,读写,NULL);
如果(!成功)失败;
}
}
void ReadFromPipe(){
德沃德读,写;
CHAR chBuf[BUFSIZE];
布尔成功=假;
句柄pStdOut=GetStdHandle(标准输出句柄);
对于(;;)
{
success=ReadFile(r1,chBuf,BUFSIZE,&read,NULL);
如果(!success | | read==0)中断;
success=WriteFile(pStdOut、chBuf、read和writed,NULL);
如果(!成功)失败;
}
}
int main()
{
德沃德·德雷德;
CHAR chBuf[BUFSIZE];
BOOL bsucces=假;
安全属性secAttr;
secAttr.nLength=sizeof(安全属性);
secAttr.bInheritHandle=TRUE;
secAttr.lpSecurityDescriptor=NULL;
printf(“创建第一个管道”);
如果(!CreatePipe(&r1,&w1,&secAttr,0)){
printf(“\n创建第一个管道时出错\n”);
}
printf(“创建第二个管道”);
如果(!CreatePipe(&r2,&w2,&secAttr,0)){
printf(“创建第二个管道时出错”);
}
if(!SetHandleInformation(r1,句柄\标志\继承,0)){
printf(“r1 SetHandleInformation\n”);
}
if(!SetHandleInformation(w2,句柄\标志\继承,0)){
printf(“w2 SetHandleInformation\n”);
}
printf(“\n正在创建子进程…\n”);
CreateChildProcess();
WriteToPipe();
ReadFromPipe();
返回0;
}
Child.cpp
#包括
#包括
#包括“pch.h”
#定义BUFSIZE 4096
int main()
{
德沃德·德雷德;
CHAR chBuf[BUFSIZE];
布尔成功=假;
句柄stdIn=GetStdHandle(标准输入句柄);
句柄stdOut=GetStdHandle(标准输出句柄);
if(stdIn==无效的| | | stdOut==无效的|句柄|值){
出境手续(1);
}
对于(;;){
success=ReadFile(stdIn、chBuf、BUFSIZE和dRead,NULL);
如果(!success | | dRead==0)中断;
success=WriteFile(stdOut、chBuf、dRead和dwrited,NULL);
如果(!成功)失败;
}
返回0;
}

由于子进程的StdIn句柄设置为“r2”,您将无法在父StdOut上显示在子进程StdIn上写入的内容。这样您就无法手动在子进程中插入任何内容。我建议使用,这样孩子的std手柄就不会与其他管道手柄混合

for(;;)等于while(1),并且ReadFile()在收到数据之前不会返回,因此如果没有发生异常(排除没有传入的数据),循环将永远不会中断,代码也不会转到ReadFromPipe()


使用namepipe的重叠模式,或者尝试创建两个线程和两个namepipe,一个从namepipe读取,然后打印输出,另一个从stdin读取,然后写入namepipe(在两个进程中)。

进程到底在什么点停止?你观察到了什么?为什么你认为这是一个死锁?你从不关闭管道手柄。另外,父进程似乎无缘无故地通过std输入输出进行读写。当然,这里出现了死锁,因为使用同步io,两个进程都从ReadFile开始。使用异步io,仅使用单管对。按调试器中的“中断”按钮,检查调用堆栈,查看代码中死锁发生的位置。@zett42-在具体情况下,即使是直接调用
ReadFile
-此同步调用(如果所有参数正确)在数据未写入管道之前不返回。但这两个过程都是从
ReadFile
开始的。