控制台程序中的线程和管道

      问题是:如何创建一个可能阻塞的程序,但在阻塞的时候能当数据可读的时候从stdour和stderr中接收数据。本文的目的是展示如何在控制台程序中使用多线程。
子进程程序:

 

Threads and Pipes in Console Apps_icoint _tmain(int argc, _TCHAR* argv[])
Threads and Pipes in Console Apps_子线程_02Threads and Pipes in Console Apps_html_03Threads and Pipes in Console Apps_ico_04{
Threads and Pipes in Console Apps_数据_05 for(int i = 0; i < 100; i++)
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07     Threads and Pipes in Console Apps_ico_04{ /**//* test */
Threads and Pipes in Console Apps_数据_05      int r = rand();
Threads and Pipes in Console Apps_数据_05      if(r & 0x100)
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07         Threads and Pipes in Console Apps_ico_04{ /**//* stderr */
Threads and Pipes in Console Apps_数据_05          _ftprintf(stderr, _T("%4d: error\n"), i);
Threads and Pipes in Console Apps_数据_05          fflush(stderr);
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07         } /**//* stderr */
Threads and Pipes in Console Apps_数据_05      else
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07         Threads and Pipes in Console Apps_ico_04{ /**//* stdout */
Threads and Pipes in Console Apps_数据_05          _ftprintf(stdout, _T("%4d: output\n"), i);
Threads and Pipes in Console Apps_数据_05          fflush(stdout);
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07         } /**//* stdout */
Threads and Pipes in Console Apps_数据_05      int w = rand() % 500;
Threads and Pipes in Console Apps_数据_05      Sleep(200 + w);
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07     } /**//* test */
Threads and Pipes in Console Apps_数据_05     return 0;
Threads and Pipes in Console Apps_数据_31}    
Threads and Pipes in Console Apps_ico

        程序创建了两个线程:一个线程处理stdout,另一个线程处理stdin,主线程从两个工作线程收集数据并显示数据,当两个工作线程都结束时,主线程就结束。现在的问题是用什么机制来实现。作者使用了进程间队列机制,I/O完成端口,

Threads and Pipes in Console Apps_icoclass CommandLine 
Threads and Pipes in Console Apps_子线程_02Threads and Pipes in Console Apps_html_03Threads and Pipes in Console Apps_ico_04{
Threads and Pipes in Console Apps_数据_05    public:
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       CommandLine() Threads and Pipes in Console Apps_ico_04{ HTML = FALSE; IsUnicode = FALSE; program = NULL; }
Threads and Pipes in Console Apps_数据_05       BOOL HTML;//是否使用html
Threads and Pipes in Console Apps_数据_05       BOOL IsUnicode;//是否使用unicode
Threads and Pipes in Console Apps_数据_05       LPTSTR program;//目标程序名称
Threads and Pipes in Console Apps_数据_31}; // class CommandLine
Threads and Pipes in Console Apps_ico
Threads and Pipes in Console Apps_ico

父进程程序:

Threads and Pipes in Console Apps_ico int _tmain(int argc, _TCHAR* argv[])
Threads and Pipes in Console Apps_子线程_02Threads and Pipes in Console Apps_html_03   Threads and Pipes in Console Apps_ico_04{
Threads and Pipes in Console Apps_数据_05    CommandLine cmd;
Threads and Pipes in Console Apps_数据_05    for(int i = 1; i < argc; i++)
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       Threads and Pipes in Console Apps_ico_04{ /**//* scan args */
Threads and Pipes in Console Apps_数据_05        CString arg = argv[i];
Threads and Pipes in Console Apps_数据_05        if(arg[0] == _T('-'))
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07           Threads and Pipes in Console Apps_ico_04{ /**//* option */
Threads and Pipes in Console Apps_数据_05            if(arg == _T("-u"))
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07               Threads and Pipes in Console Apps_ico_04{ /**//* unicode */
Threads and Pipes in Console Apps_数据_05                cmd.IsUnicode = TRUE;//使用unicode
Threads and Pipes in Console Apps_数据_05                continue;
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07               } /**//* unicode */
Threads and Pipes in Console Apps_数据_05            if(arg == _T("-html"))
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07               Threads and Pipes in Console Apps_ico_04{ /**//* html */
Threads and Pipes in Console Apps_数据_05                cmd.HTML = TRUE;//使用html
Threads and Pipes in Console Apps_数据_05                continue;
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07               } /**//* html */
Threads and Pipes in Console Apps_数据_05            _ftprintf(stderr, _T("Unrecognized option \"%s\"\n"), arg);
Threads and Pipes in Console Apps_数据_05            return Result::INVALID_ARGUMENT;
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07           } /**//* option */
Threads and Pipes in Console Apps_数据_05        if(cmd.program != NULL)
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07           Threads and Pipes in Console Apps_ico_04{ /**//* two files */
Threads and Pipes in Console Apps_数据_05            _ftprintf(stderr, _T("Two command directives given:\n  [1] \"%s\"\n  [2]\"%s\"\n"),
Threads and Pipes in Console Apps_数据_05                      cmd,
Threads and Pipes in Console Apps_数据_05                      arg);
Threads and Pipes in Console Apps_数据_05            return Result::TWO_COMMANDS;        
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07           } /**//* two files */
Threads and Pipes in Console Apps_数据_05        cmd.program = argv[i];//目标程序名称
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       } /**//* scan args */
Threads and Pipes in Console Apps_数据_05    if(cmd.program == NULL)
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       Threads and Pipes in Console Apps_ico_04{ /**//* no args */
Threads and Pipes in Console Apps_数据_05        _ftprintf(stderr, _T("need program to run\n"));
Threads and Pipes in Console Apps_数据_05        return Result::NO_PROGRAM;
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       } /**//* no args */
Threads and Pipes in Console Apps_数据_05    SmartHandle iocp = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);//创建IO完成端口
Threads and Pipes in Console Apps_数据_05
Threads and Pipes in Console Apps_数据_05    if(iocp == NULL)
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       Threads and Pipes in Console Apps_ico_04{ /**//* failed iocp */
Threads and Pipes in Console Apps_数据_05        DWORD err = ::GetLastError();
Threads and Pipes in Console Apps_数据_05        _ftprintf(stderr, _T("CreateIoCompletionPort failed, error %s\n"), ErrorString(err));
Threads and Pipes in Console Apps_数据_05        return Result::IOCP_FAILED;
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       } /**//* failed iocp */
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07    SECURITY_ATTRIBUTES sa = Threads and Pipes in Console Apps_ico_04{sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
Threads and Pipes in Console Apps_数据_05    SmartHandle stdout_read;
Threads and Pipes in Console Apps_数据_05    SmartHandle stdout_write;
Threads and Pipes in Console Apps_数据_05    SmartHandle stderr_read;
Threads and Pipes in Console Apps_数据_05    SmartHandle stderr_write;
Threads and Pipes in Console Apps_数据_05    static const UINT PIPE_BUFFER_SIZE = 32;//管道缓冲区大小
Threads and Pipes in Console Apps_数据_05    //创建管道
Threads and Pipes in Console Apps_数据_05    if(!::CreatePipe((LPHANDLE)stdout_read, (LPHANDLE)stdout_write, &sa, PIPE_BUFFER_SIZE))
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       Threads and Pipes in Console Apps_ico_04{ /**//* failed stdout */
Threads and Pipes in Console Apps_数据_05        DWORD err = ::GetLastError();
Threads and Pipes in Console Apps_数据_05        _tprintf(_T("stdout pipe failure: %s\n"), ErrorString(err));
Threads and Pipes in Console Apps_数据_05        return Result::STDOUT_CREATION_FAILED;
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       } /**//* failed stdout */
Threads and Pipes in Console Apps_数据_05    //创建管道
Threads and Pipes in Console Apps_数据_05    if(!::CreatePipe((LPHANDLE)stderr_read, (LPHANDLE)stderr_write, &sa, PIPE_BUFFER_SIZE))
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       Threads and Pipes in Console Apps_ico_04{ /**//* failed stderr */
Threads and Pipes in Console Apps_数据_05        DWORD err = ::GetLastError();
Threads and Pipes in Console Apps_数据_05        _tprintf(_T("stderr pipe failure: %s\n"), ErrorString(err));
Threads and Pipes in Console Apps_数据_05        return Result::STDERR_CREATION_FAILED;
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       } /**//* failed stderr */
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07    STARTUPINFO startup = Threads and Pipes in Console Apps_ico_04{sizeof(STARTUPINFO)};
Threads and Pipes in Console Apps_数据_05    startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
Threads and Pipes in Console Apps_数据_05    startup.wShowWindow = SW_HIDE;
Threads and Pipes in Console Apps_数据_05    //子进程使用的标准输入和标准输出是父进程的写管道
Threads and Pipes in Console Apps_数据_05    startup.hStdOutput = stdout_write;
Threads and Pipes in Console Apps_数据_05    startup.hStdError = stderr_write;
Threads and Pipes in Console Apps_数据_05    PROCESS_INFORMATION procinfo;
Threads and Pipes in Console Apps_数据_05    //创建子进程,重定向标准输出和标准错误
Threads and Pipes in Console Apps_数据_05    if(!::CreateProcess(NULL, cmd.program, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &startup, &procinfo))
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       Threads and Pipes in Console Apps_ico_04{ /**//* failed */
Threads and Pipes in Console Apps_数据_05        DWORD err = ::GetLastError();
Threads and Pipes in Console Apps_数据_05        _tprintf(_T("CreateProcess failed for \"%s\": %s"), cmd.program, ErrorString(err));
Threads and Pipes in Console Apps_数据_05        return Result::CREATEPROCESS_FAILED;
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       } /**//* failed */
Threads and Pipes in Console Apps_数据_05    ::CloseHandle(procinfo.hProcess);   // handle will never be needed
Threads and Pipes in Console Apps_数据_05    ::CloseHandle(procinfo.hThread);    // handle will never be needed
Threads and Pipes in Console Apps_数据_05    //在父进程这端关闭子进程要使用的管道端口
Threads and Pipes in Console Apps_数据_05    stdout_write.Close();               // Close our end of the pipe
Threads and Pipes in Console Apps_数据_05    stderr_write.Close();               // Close our end of the pipe
Threads and Pipes in Console Apps_数据_05    unsigned id;
Threads and Pipes in Console Apps_数据_05    //创建处理stdout的子线程
Threads and Pipes in Console Apps_数据_05    SmartHandle stdoutThread = (HANDLE)_beginthreadex(NULL, 0, reader, new ThreadParms(stdout_read, SourceFlags::StdOut, iocp, cmd.IsUnicode), 0, &id);
Threads and Pipes in Console Apps_数据_05    if(stdoutThread == NULL)
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       Threads and Pipes in Console Apps_ico_04{ /**//* thread create failed */
Threads and Pipes in Console Apps_数据_05        DWORD err = ::GetLastError();
Threads and Pipes in Console Apps_数据_05        _ftprintf(stderr, _T("Thread creation for stdout failed, error %s\n"), ErrorString(err));
Threads and Pipes in Console Apps_数据_05        return Result::THREAD_FAILURE;
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       } /**//* thread create failed */        
Threads and Pipes in Console Apps_数据_05
Threads and Pipes in Console Apps_数据_05    stdoutThread.Close(); // handle will never be used
Threads and Pipes in Console Apps_数据_05    //创建处理stderr的子线程
Threads and Pipes in Console Apps_数据_05    SmartHandle stderrThread = (HANDLE)_beginthreadex(NULL, 0, reader, new ThreadParms(stderr_read, SourceFlags::StdErr, iocp, cmd.IsUnicode), 0, &id);
Threads and Pipes in Console Apps_数据_05    if(stderrThread == NULL)
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       Threads and Pipes in Console Apps_ico_04{ /**//* thread create failed */
Threads and Pipes in Console Apps_数据_05        DWORD err = ::GetLastError();
Threads and Pipes in Console Apps_数据_05        _ftprintf(stderr, _T("Thread creation for stderr failed, error %s\n"), ErrorString(err));
Threads and Pipes in Console Apps_数据_05        return Result::THREAD_FAILURE;
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       } /**//* thread create failed */        
Threads and Pipes in Console Apps_数据_05    stderrThread.Close(); // handle will never be used
Threads and Pipes in Console Apps_数据_05    SourceFlags::FlagType broken = SourceFlags::None;
Threads and Pipes in Console Apps_数据_05    Result::Type result = Result::SUCCESS;
Threads and Pipes in Console Apps_数据_05    while(broken != (SourceFlags::StdOut | SourceFlags::StdErr))
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       Threads and Pipes in Console Apps_ico_04{ /**//* watch pipes */
Threads and Pipes in Console Apps_数据_05       //异步方式监控管道
Threads and Pipes in Console Apps_数据_05        OVERLAPPED * ovl;
Threads and Pipes in Console Apps_数据_05        DWORD bytesRead;
Threads and Pipes in Console Apps_数据_05        ULONG_PTR key;
Threads and Pipes in Console Apps_数据_05        //获取完成端口队列状态,获取从两个子线程到来的数据,key表明来自哪个线程已经完成了I/O操作,bytesRead表明数据来源
Threads and Pipes in Console Apps_数据_05        BOOL ok = ::GetQueuedCompletionStatus(iocp, &bytesRead, &key, &ovl, INFINITE);
Threads and Pipes in Console Apps_数据_05        if(!ok)
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07           Threads and Pipes in Console Apps_ico_04{ /**//* failed */
Threads and Pipes in Console Apps_数据_05            DWORD err = ::GetLastError();
Threads and Pipes in Console Apps_数据_05            result = Result::IOCP_ERROR;
Threads and Pipes in Console Apps_数据_05            _ftprintf(stderr, _T("GetQueuedCompletionStatus failed, error %s\n"), ErrorString(err));
Threads and Pipes in Console Apps_数据_05            break;
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07           } /**//* failed */
Threads and Pipes in Console Apps_数据_05       broken = (SourceFlags::FlagType)(broken | (int)key);
Threads and Pipes in Console Apps_数据_05       //终止信号到来
Threads and Pipes in Console Apps_数据_05        if(key != 0)
Threads and Pipes in Console Apps_数据_05           continue;  // termination notifications contain no data
Threads and Pipes in Console Apps_数据_05        //输出数据
Threads and Pipes in Console Apps_数据_05        CString * s = (CString *)ovl;
Threads and Pipes in Console Apps_数据_05        WriteToOutput(*s, (SourceFlags::FlagType)bytesRead, cmd);
Threads and Pipes in Console Apps_数据_05        delete s;
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       } /**//* watch pipes */
Threads and Pipes in Console Apps_数据_05    stdout_read.Close();
Threads and Pipes in Console Apps_数据_05    stderr_read.Close();
Threads and Pipes in Console Apps_数据_05    return result;
Threads and Pipes in Console Apps_数据_31   }  // _tmain
Threads and Pipes in Console Apps_ico

 

智能句柄类

用来处理句柄的生存期问题:

 

 

Threads and Pipes in Console Apps_icoclass SmartHandle 
Threads and Pipes in Console Apps_子线程_02Threads and Pipes in Console Apps_html_03Threads and Pipes in Console Apps_ico_04{//智能句柄类
Threads and Pipes in Console Apps_数据_05    public:
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       SmartHandle() Threads and Pipes in Console Apps_ico_04{ handle = NULL; }
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       SmartHandle(HANDLE h) Threads and Pipes in Console Apps_ico_04{ handle = h; }
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       virtual ~SmartHandle() Threads and Pipes in Console Apps_ico_04{ Close();}
Threads and Pipes in Console Apps_数据_05    public:
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       operator HANDLE() Threads and Pipes in Console Apps_ico_04{ return handle; }
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       operator LPHANDLE() Threads and Pipes in Console Apps_ico_04{ return & handle; }
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       bool operator==(HANDLE h) Threads and Pipes in Console Apps_ico_04{ return handle == h; }
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       SmartHandle & operator=(HANDLE h) Threads and Pipes in Console Apps_ico_04{ handle = h; return *this; }
Threads and Pipes in Console Apps_数据_05    public:
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       void Close() Threads and Pipes in Console Apps_ico_04{ if(handle != NULL) ::CloseHandle(handle); handle = NULL; }
Threads and Pipes in Console Apps_数据_05    protected:
Threads and Pipes in Console Apps_数据_05       HANDLE handle;
Threads and Pipes in Console Apps_数据_31};
Threads and Pipes in Console Apps_ico

线程参数类:

Threads and Pipes in Console Apps_icoclass ThreadParms
Threads and Pipes in Console Apps_子线程_02Threads and Pipes in Console Apps_html_03Threads and Pipes in Console Apps_ico_04{//线程参数
Threads and Pipes in Console Apps_数据_05    public:
Threads and Pipes in Console Apps_数据_05       ThreadParms(HANDLE h, SourceFlags::FlagType f, HANDLE io, BOOL uni) 
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       Threads and Pipes in Console Apps_ico_04{
Threads and Pipes in Console Apps_数据_05          stream = h;
Threads and Pipes in Console Apps_数据_05          flags = f;
Threads and Pipes in Console Apps_数据_05          iocp = io;
Threads and Pipes in Console Apps_数据_05          IsUnicode = uni;
Threads and Pipes in Console Apps_ico_276       }
Threads and Pipes in Console Apps_数据_05    public:
Threads and Pipes in Console Apps_数据_05       HANDLE stream;//管道读端口
Threads and Pipes in Console Apps_数据_05       SourceFlags::FlagType flags;//指明数据源
Threads and Pipes in Console Apps_数据_05       HANDLE iocp;//I/O完成端口
Threads and Pipes in Console Apps_数据_05       BOOL IsUnicode;//是否使用unicode
Threads and Pipes in Console Apps_数据_31};
Threads and Pipes in Console Apps_ico

   

 

DWORD NumberOfBytesTransferred

ULONG_PTR CompletionKey

LPOVERLAPPED Overlapped

Meaning

SourceFlags::StdOut

0

(LPOVERLAPPED)(CString *)

stdout line to display

SourceFlags::StdErr

0

(LPOVERALLPED)(CString *)

stderr line to display

0

SourceFlags::StdOut

NULL

stdout has terminated

0

SourceFlags::StdErr

NULL

stderr has terminated

读线程工作函数

Threads and Pipes in Console Apps_icoUINT __stdcall reader(LPVOID p)
Threads and Pipes in Console Apps_子线程_02Threads and Pipes in Console Apps_html_03    Threads and Pipes in Console Apps_ico_04{//读线程工作函数
Threads and Pipes in Console Apps_数据_05     ThreadParms * parms = (ThreadParms *)p;
Threads and Pipes in Console Apps_数据_05     PipeReader pipe(parms->stream, parms->IsUnicode);//创建管道读者
Threads and Pipes in Console Apps_数据_05     CString Prefix;
Threads and Pipes in Console Apps_数据_05     while(TRUE)
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07        Threads and Pipes in Console Apps_ico_04{ /**//* processing loop */
Threads and Pipes in Console Apps_数据_05         //读管道数据
Threads and Pipes in Console Apps_数据_05         if(!pipe.Read())
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07            Threads and Pipes in Console Apps_ico_04{ /**//* failed stream */
Threads and Pipes in Console Apps_数据_05             break;
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07            } /**//* failed stream */
Threads and Pipes in Console Apps_数据_05         FormatAndOutput(pipe.GetString(), Prefix, parms);
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07        } /**//* processing loop */
Threads and Pipes in Console Apps_数据_05     if(!Prefix.IsEmpty())
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07        Threads and Pipes in Console Apps_ico_04{ /**//* write out last line */
Threads and Pipes in Console Apps_数据_05         CString text(_T("\r\n"));
Threads and Pipes in Console Apps_数据_05         FormatAndOutput(text, Prefix, parms);
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07        } /**//* write out last line */
Threads and Pipes in Console Apps_数据_05      //posts an I/O completion packet to an I/O completion port
Threads and Pipes in Console Apps_数据_05     //发出完成信息,没有数据,因此第二个参数为,第三个参数表明完成的是哪个
Threads and Pipes in Console Apps_数据_05     ::PostQueuedCompletionStatus(parms->iocp, 0, parms->flags, NULL);
Threads and Pipes in Console Apps_数据_05     delete parms;
Threads and Pipes in Console Apps_数据_05     return 0;
Threads and Pipes in Console Apps_数据_31} // reader
Threads and Pipes in Console Apps_icoclass PipeReader 
Threads and Pipes in Console Apps_子线程_02Threads and Pipes in Console Apps_html_03Threads and Pipes in Console Apps_ico_04{//管道读者
Threads and Pipes in Console Apps_数据_05    protected:
Threads and Pipes in Console Apps_数据_05       static const UINT MAX_BUFFER = 1024;//缓存大小
Threads and Pipes in Console Apps_数据_05    public:
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       PipeReader(HANDLE str, BOOL uni) Threads and Pipes in Console Apps_ico_04{ Init(); stream = str; IsUnicode = uni; }
Threads and Pipes in Console Apps_数据_05       CString GetString() 
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       Threads and Pipes in Console Apps_ico_04
Threads and Pipes in Console Apps_数据_05           if(IsUnicode) 
Threads and Pipes in Console Apps_数据_05               return CString((LPCWSTR)buffer); 
Threads and Pipes in Console Apps_数据_05           else 
Threads and Pipes in Console Apps_数据_05               return CString((LPCSTR)buffer); 
Threads and Pipes in Console Apps_ico_276       }
Threads and Pipes in Console Apps_数据_05       BOOL Read() 
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       Threads and Pipes in Console Apps_ico_04{//从管道中读取数据
Threads and Pipes in Console Apps_数据_05          if(Offset == 1)
Threads and Pipes in Console Apps_数据_05             buffer[0] = reread;
Threads and Pipes in Console Apps_数据_05          if(!ReadFile(stream, &buffer[Offset], MAX_BUFFER - (IsUnicode ? sizeof(WCHAR) : sizeof(char)), &bytesRead, NULL))
Threads and Pipes in Console Apps_数据_05             return FALSE;
Threads and Pipes in Console Apps_数据_05          if(IsUnicode)
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07             Threads and Pipes in Console Apps_ico_04{ /**//* unicode pipe */
Threads and Pipes in Console Apps_数据_05              if((Offset + bytesRead) & 1)
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07                 Threads and Pipes in Console Apps_ico_04{ /**//* odd bytes read */
Threads and Pipes in Console Apps_数据_05                  Offset = 1; // offset for next read
Threads and Pipes in Console Apps_数据_05                  reread = buffer[Offset + bytesRead - 1]; // force reread
Threads and Pipes in Console Apps_数据_05                  buffer[Offset + bytesRead - 1] = 0; // remove from current buffer
Threads and Pipes in Console Apps_数据_05                  bytesRead--;   // pretend we didn't see it
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07                 } /**//* odd bytes read */
Threads and Pipes in Console Apps_数据_05              else
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07                 Threads and Pipes in Console Apps_ico_04{ /**//* even bytes read */
Threads and Pipes in Console Apps_数据_05                  Offset = 0; // offset for next read
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07                 } /**//* even bytes read */
Threads and Pipes in Console Apps_数据_05              buffer[Offset + bytesRead] = 0;
Threads and Pipes in Console Apps_数据_05              buffer[Offset + bytesRead + 1] = 0; // create Unicode NUL
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07             } /**//* unicode pipe */
Threads and Pipes in Console Apps_数据_05          else
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07             Threads and Pipes in Console Apps_ico_04{ /**//* ANSI pipe */
Threads and Pipes in Console Apps_数据_05              buffer[bytesRead] = '\0';
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07             } /**//* ANSI pipe */
Threads and Pipes in Console Apps_数据_05         return TRUE;
Threads and Pipes in Console Apps_ico_276       } // PipeReader::Read
Threads and Pipes in Console Apps_数据_05    protected:
Threads and Pipes in Console Apps_父进程_06Threads and Pipes in Console Apps_html_07       void Init() Threads and Pipes in Console Apps_ico_04{ stream = NULL; Offset = 0; IsUnicode = FALSE; }
Threads and Pipes in Console Apps_数据_05       BOOL IsUnicode;//是否使用unicode
Threads and Pipes in Console Apps_数据_05       HANDLE stream;//管道读端口
Threads and Pipes in Console Apps_数据_05    protected:
Threads and Pipes in Console Apps_数据_05       BYTE buffer[MAX_BUFFER];//缓冲区
Threads and Pipes in Console Apps_数据_05       DWORD Offset;
Threads and Pipes in Console Apps_数据_05       BYTE reread;
Threads and Pipes in Console Apps_数据_05       DWORD bytesRead;
Threads and Pipes in Console Apps_数据_31}; // class PipeReader
Threads and Pipes in Console Apps_ico

小结

    子进程往管道的两个写端口写数据,父进程从管道的两个读端口读数据,为了读数据,父进程创建了两个子线程,一个子线程从stdout中读数据,一个子线程从stderr中读数据,为了能异步读取数据,使用了I/O完成端口。