Я пытаюсь прочитать из stderr
дочернего процесса. Данные представляют собой строки текста, созданные с помощью sprintf(stderr, "some debug info\n")
. Я использую ReadFileE
x с подпрограммой завершения. Я не знаю, сколько строк текста или какой длины будет каждая строка. Итак, что мне указать в качестве параметра nNumberOfBytesToRead
?
Я предполагаю, что я установил максимальный размер моего буфера, который я сделаю 4k; хотя я не знаю, является ли это оптимальным размером. Я предполагаю, что если строка, записанная в stderr
, короче 4 КБ, процедура завершения не сработает. Я предполагаю, что когда 4 КБ достигнуто, но остается больше данных, мне нужно запустить еще один ReadFileEx
в рамках процедуры завершения. Я буду знать, что это так, потому что GetLastError
вернет ERROR_MORE_DATA
. Я надеюсь, что мне позвонят, когда буфер не заполнен, но дочерний процесс завершился. Я не уверен, что получаю обратный вызов завершения, когда дочерний процесс выходит, потому что я передал дескриптор записи stderr
дочернему процессу, когда я его создал; возможно, я получу обратный вызов, когда я закрою этот дескриптор. Есть ли какие-либо условия гонки, когда ребенок закрывает wrt
от моего чтения 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)
Подробности (расширение Tx — это оболочка, которая выдает ошибки):
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;
}
CreatePipe
? - person Ross Ridge   schedule 23.07.2014