首页 > 解决方案 > 进程完成时如何使Windows Pipe添加EOF

问题描述

我正在 Windows 上创建一个模拟管道的递归 C 函数。

到目前为止,这是我的功能:


static BOOL execute_in_pipe(char (*cmdline)[1024], char *env, int index,
    int pipe_length, STARTUPINFO *old_suinfo, HANDLE proc_handles[])
{
    //Create new startup info
    STARTUPINFO suinfo;
    memset(&suinfo, 0, sizeof(suinfo));
    suinfo.cb = sizeof(suinfo);

    //Create new process info
    PROCESS_INFORMATION pinfo;

    //Make pipe
    HANDLE pipe_out_rd, pipe_out_wr;
    if(index > 0) {
        HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);

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

        if (! CreatePipe(&pipe_out_rd, &pipe_out_wr, &sa, 0))
        {
            CloseHandle(pipe_out_wr);
            CloseHandle(pipe_out_rd);
            //res.tag = NATIVE_ERR_PIPE_FAILED;
            //return res;
        }

        //Set output of last process to write handle
        if((*old_suinfo).hStdInput == 0) {
            (*old_suinfo).hStdInput = hIn;
        }
        (*old_suinfo).hStdOutput = pipe_out_wr;
        (*old_suinfo).dwFlags = STARTF_USESTDHANDLES;

        //Set input of this process to read handle
        suinfo.hStdInput = pipe_out_rd;
        if(index >= pipe_length-1) {
            suinfo.hStdOutput = hOut;
        }
        suinfo.dwFlags = STARTF_USESTDHANDLES;
    }

    BOOL result = TRUE;
    if(index < pipe_length-1) {
        result = execute_in_pipe(cmdline, env, index+1, pipe_length, &suinfo, proc_handles);
    }

    //Return whether creating process succeeds
    if(!CreateProcess(NULL, cmdline[index], NULL, NULL,
        (pipe_length>1), 0, env, NULL, &suinfo, &pinfo))
    {
        return FALSE;
    }

    CloseHandle(pinfo.hThread);

    proc_handles[index] = pinfo.hProcess;

    return result;
}

我制作了两个 c 程序来测试管道:

种子.c

#include <stdio.h>

int main() {
   printf("Hello");
}

附加.c

#include <stdio.h>
#include <string.h>

int main() {
   char str[200];
   scanf( "%s", str );

   printf("%s World!", str);
}

我使用以下方法调用这些函数:

    STARTUPINFO suinfo;
    HANDLE proc_handles[2];
    printf("Starting\n");
    char cmdline[2][1024] = {"seed.exe", "append.exe"};

    execute_in_pipe(cmdline, 0, 0, 2, &suinfo, proc_handles);

    WaitForMultipleObjects(2, proc_handles, TRUE, INFINITE);

调用此函数时,控制台会打印出“Starting”,然后等待……永远……

我很确定原因是 scanf 正在尝试读取整行(直到某种分隔符)。当我将 seed.c 更新为 `printf("Hello\n") 时,它运行良好。

所以,是的,这只是一个规则吗?所有管道进程都应该使用换行符吗?

好吧,调用seed.exe | append.exe命令提示符效果很好!即使没有换行符!我的代码缺少什么?

编辑:正如一些人所指出的,当所有管道都关闭时,Unix 管道会进入“流结束”(不是我最初认为的 EOF)。在测试 Unix 管道系统时,没有出现这个问题,所以 end-of-stream 就像一个分隔符。Windows会做类似的事情吗?如果是这样,我是否必须关闭某些东西才能使其结束流?

标签: cwindowswinapipipe

解决方案


您应该使用命名管道而不是未命名管道来执行 I/O 重定向。当服务器的管道句柄关闭时,客户端上的 scanf() 将知道它并停止等待换行符。

下面的代码是帕斯卡,但不是很难理解。

const
  BUFSIZE:integer = 512;
  Pipename:String = '\\.\pipe\devcpp_run';

InputWrite := CreateNamedPipe(
      pAnsiChar(Pipename),             // pipe name
      PIPE_ACCESS_OUTBOUND,       // read/write access
      PIPE_TYPE_BYTE or       // message type pipe
      PIPE_READMODE_BYTE or   // message-read mode
      PIPE_WAIT,                // blocking mode
      PIPE_UNLIMITED_INSTANCES, // max. instances
      BUFSIZE,                  // output buffer size
      BUFSIZE,                  // input buffer size
      0,                        // client time-out
      nil);                    // default security attribute
if InputWrite = INVALID_HANDLE_VALUE then begin
      Exit;
end;
InputRead := CreateFile(
     PAnsiChar(Pipename),   // pipe name
     GENERIC_READ,
     0,              // no sharing
     @sa,           // default security attributes
     OPEN_EXISTING,  // opens existing pipe
     0,              // default attributes
     0);
if InputRead = INVALID_HANDLE_VALUE then begin
  Exit;
end;
StartupInfo.dwFlags := StartupInfo.dwFlags or STARTF_USESTDHANDLES;
StartupInfo.hStdInput := InputRead;
StartupInfo.hStdOutput := 7; // Undocumented Handle of Console Output
StartupInfo.hStdError := 11; // Undocumented Handle of Console Error Output
end;

推荐阅读