使用ReadFile和WriteFile时出现死锁

时间:2018-12-09 18:48:52

标签: c++ winapi

我正在做一个学校项目,试图在子进程的StdOut上显示父进程的StdIn中写的内容。反之亦然,即在父StdOut上显示子进程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;
   }

1 个答案:

答案 0 :(得分:0)

您将无法在父级StdOut上显示子进程StdIn上写的内容,因为子进程的stdIn Handle设置为“ r2”。因此,您将无法在子进程中手动插入任何内容。我建议使用namepipe,以使孩子的std手柄不会与其他管道手柄混合。

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

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