2014-07-23 5 views
0

자식 프로세스의 stderr에서 읽으려고합니다. 데이터는 sprintf(stderr, "some debug info\n")으로 작성된 텍스트 행입니다. 완료 루틴과 함께 ReadFileE x를 사용하고 있습니다. 나는 얼마나 많은 문장의 줄이나 각 줄이 얼마나 길어야할지 모른다. 그래서 nNumberOfBytesToRead 매개 변수로 무엇을 넣을까요?ReadFileEx, 가변 길이 - 몇 가지 질문

내 생각 엔 4k를 만들 버퍼의 최대 크기를 넣었습니다. 그게 최적의 크기인지는 모르겠지만. stderr에 쓰여진 줄이 4k보다 짧으면 완료 루틴이 실행되지 않는다고 추측합니다. 나는 4k에 도달했지만 더 많은 데이터가 남아있을 때 완료 루틴 내에서 다른 ReadFileEx을 발사해야한다고 생각합니다. GetLastErrorERROR_MORE_DATA을 반환 할 것이므로이 경우를 알 수 있습니다. 버퍼가 꽉 찼지 만 자식 프로세스가 종료되었을 때 전화를 받기를 바라고 있습니다. 자식 프로세스가 종료 될 때 완료 콜백을 얻었는지 확신 할 수 없습니다. 왜냐하면 자식을 만들 때 stderr 쓰기 핸들을 전달했기 때문입니다. 어쩌면 내가 내가 그 핸들을 닫을 때 콜백을 얻을 수 있습니다. 자녀가 을 내 독서 인 stderr으로 닫을 때 경쟁 조건이 있습니까?

Attr.bInheritHandle = true 
CreatePipe(&hr, &hw, &Attr, 0) and SetHandleInformation(hX, HANDLE_FLAG_INHERIT) on hX the child uses. 
Si.hStdXXX = handles from CreatePipe that child uses 
CreateProcess(inherit=true, &Si) 

세부 사항 (전송 확장은 오류를 발생 래퍼) : : 여기

프로세스와 핸들이 만들어지는 방법의 사이비 코드 CreatePipe로 만든

HANDLE Create() { 
    STARTUPINFO SI, *pSI = NULL; 
    bool fInherit = m_fInherit; 
    if (m_fStdOut || m_fStdIn || m_fStdErr) { 
     fInherit = true; 
     SECURITY_ATTRIBUTES Attr; 
     Attr.nLength = sizeof(SECURITY_ATTRIBUTES); 
     Attr.bInheritHandle = TRUE; 
     Attr.lpSecurityDescriptor = NULL; 
     if (m_fStdOut) // Create a pipe for the child process's STDOUT. The child will use the write. 
      CHandle::CreatePipe(m_hStdOutR, m_hStdOutW, &Attr, CP_INHERIT_WRITE); 
     if (m_fStdErr) // Create a pipe for the child process's STDERR. The child will use the write. 
      CHandle::CreatePipe(m_hStdErrR, m_hStdErrW, &Attr, CP_INHERIT_WRITE); 
     if (m_fStdIn) // Create a pipe for the child process's STDIN. The child will use the read. 
      CHandle::CreatePipe(m_hStdInR, m_hStdInW, &Attr, CP_INHERIT_READ); 
     // Set up members of the STARTUPINFO structure. 
     // This structure specifies the STDIN and STDOUT handles for redirection. 
     ZeroStruct(SI); 
     SI.cb = sizeof(STARTUPINFO); 
     SI.hStdError = m_hStdErrW, SI.hStdOutput = m_hStdOutW, SI.hStdInput = m_hStdInR; 
     SI.dwFlags |= STARTF_USESTDHANDLES; 
     pSI = &SI; 
    } 
    // m_fCpu, m_fNuma are masks to set affinity to cpus or numas 
    CreateProcessTx(NULL, m_szCmdLine, fInherit, m_fFlags, pSI, &m_pi, m_fCpu, m_fNuma, 5); 
    m_hProc = m_pi.hProcess; 
    m_hThread = m_pi.hThread; 
    if (!m_fThread) 
     m_hThread.Close(); 
    return m_hProc; 
} 

static void CreatePipe(CHandle &hRead, CHandle &hWrite, SECURITY_ATTRIBUTES* pAttr, BYTE fInheritMask) { 
    HANDLE hReadTmp = NULL, hWriteTmp = NULL; 
    CreatePipeTx(hReadTmp, hWriteTmp, pAttr); 
    SetHandleInformation(hReadTmp, HANDLE_FLAG_INHERIT, (fInheritMask&CP_INHERIT_READ) ? HANDLE_FLAG_INHERIT : 0); 
    SetHandleInformation(hWriteTmp, HANDLE_FLAG_INHERIT, (fInheritMask&CP_INHERIT_WRITE) ? HANDLE_FLAG_INHERIT : 0); 
    hRead = hReadTmp; 
    hWrite = hWriteTmp; 
} 
+0

'CreatePipe'로 생성 된 핸들을 사용하고 있습니까? –

+0

@RR 좋은 지적. 파이프와 프로세스를 만드는 코드 부분을 추가하기 위해이 게시물을 편집했습니다. – johnnycrash

답변

2

익명 파이프 할 수 비동기 적으로 사용되었습니다. Windows SDK 설명서에서 :

비동기 (중복) 읽기 및 쓰기 작업은 익명 파이프에서 지원되지 않습니다. 즉, 익명 파이프에서는 ReadFileEx 및 WriteFileEx 함수를 사용할 수 없습니다. > 또한 ReadFile 및 WriteFile의 lpOverlapped 매개 변수는 익명 파이프와 함께 사용할 때 무시됩니다.

는 기본적으로 CreatePipeFILE_FLAG_OVERLAPPED 플래그를 허용하지 않으며, 비동기 I/O는 파일 핸들을 만들 때 플래그를 사용해야합니다.

명명 된 파이프를 만들려면 CreateNamedPipe을 사용해야합니다. 질문 Overlapped I/O on anonymous pipe에 대한 대답이있는 대체 기능 MyCreatePipeEx에 대한 링크가 포함되어 있습니다.

완료 포트는 다른 끝에서 닫힌 파이프에서 읽으려고 시도한 후에 길이가 0 인 읽기 이벤트를 수신해야합니다.

클라이언트 프로세스에서 다양한 양의 데이터를 읽으려면 편리한 크기를 알고 읽기 요청을 발행하고 요청한 것보다 짧은 읽기 이벤트를 처리 할 준비를하십시오. 짧지 만 영이 아닌 길이는 EOF로 해석하지 마십시오. 0 길이 읽기 또는 오류가 발생할 때까지 읽기 요청을 계속 발행하십시오.

WaitForMultipleObjects도 스레드가 alterable state 인 경우에만 호출되므로 완료 루틴과 함께 작동하지 않습니다. bAlertable 인수가 true로 설정된 WaitForMultipleObjectEx을 사용하십시오. 이 함수는 하나 이상의 완료 루틴을 실행 한 후 WAIT_IO_COMPLETION을 반환합니다. 이 경우 즉시 WaitForMultipleObjectEx으로 다시 전화하고 싶을 것입니다.

+0

ReadFileEx에 대한 호출이 차단되면서 그 결론에 도달했습니다. 내가 현재하고있는 CreateNamedPipe를 시도 할 때까지 내가 망칠 수 있다고 생각했습니다. 가변 길이 읽기에 대해 아는 것이 있습니까? – johnnycrash

+0

흠 ... 질문의 그 부분을 놓친 나는 그것을 해결하기 위해 내 대답을 업데이 트했습니다. –

+0

@RR 완료 기능을 사용하여 읽기 요청을 다시 발행합니까? 내 WaitForMultipleObjects는 여러 자식 프로세스를 기다리고 있기 때문에해야한다고 생각합니다. stderr/stdout에서 읽는 것이 전부가 아닙니다. – johnnycrash