我有一个长期运行的基于控制台的应用程序 Sender,它使用非缓冲输出(例如 cout
我问过一个单独的问题关于做到这一点的最佳方法。我的第一次尝试是为子进程创建带有重定向 STDIN 和 STDOUT 的管道,并使用异步 ReadFileEx 调用来读取发送者的数据。这无法正常工作,因为 ReadFileEx 函数仅触发一次,并且仅传输零字节,即使我知道这一事实Sender
正在发送数据。
我正在创建 2 个带有重定向 STDIN 和 STDOUT 的管道,ala这个 MS 示例:
// allow the child process to inherit handles
SECURITY_ATTRIBUTES sa = {0};
sa.nLength = sizeof(sa);
sa.bInheritHandle = 1;
// create pipes with rerouted stdin & stdout
CreatePipe(&handles[h_Child_StdOut_Read], &handles[h_Child_StdOut_Write], &sa, 0);
SetHandleInformation(handles[h_Child_StdOut_Read], HANDLE_FLAG_INHERIT, 0);
CreatePipe(&handles[h_Child_StdIn_Read], &handles[h_Child_StdIn_Write], &sa, 0);
SetHandleInformation(handles[h_Child_StdIn_Read], HANDLE_FLAG_INHERIT, 0);
...Receiver
然后继续开始Sender
通过CreateProcess():
// create child process
PROCESS_INFORMATION pi = {0};
STARTUPINFO si = {0};
si.cb = sizeof(si);
si.hStdOutput = handles[h_Child_StdOut_Write];
si.hStdInput = handles[h_Child_StdIn_Read];
si.dwFlags |= STARTF_USESTDHANDLES;
CreateProcess( 0, "Sender.EXE", 0, 0, 1, 0, 0, 0, &si, &pi);
handles[h_Child_Process] = pi.hProcess;
handles[h_Child_Thread] = pi.hThread;
我的主循环基于 WaitForObjectsEx,置于可警报等待状态以支持异步文件读取。我正在等待两个句柄:一个在何时发出信号Sender
过早死亡,并且发出信号Receiver
的主线程想要Sender
去死。在开始循环之前,我启动了重叠(异步)文件读取操作Sender
的标准输出。忽略明显的内存泄漏和其他黑客行为——这是说明性的:
vector<HANDLE> wait_handles;
wait_handles.push_back(handles[h_Die_Sig]);
wait_handles.push_back(handles[h_Child_Process]);
for( bool cont = true; cont; )
{
IO* io = new IO;
memset(io, 0, sizeof(IO));
io->buf_size_ = 16 * 1024;
io->buf_ = new char[io->buf_size_];
memset(io->buf_, 0, io->buf_size_);
io->thread_ = ¶m;
io->file_ = handles[h_Child_StdOut_Read];
if( !ReadFileEx(io->file_, io->buf_, io->buf_size_, io, OnFileRead) )
{
DWORD err = GetLastError();
string err_msg = util::strprintwinerr(err);
}
DWORD rc = WaitForMultipleObjectsEx(wait_handles.size(), &wait_handles[0], FALSE, INFINITE, TRUE);
// ...
}
The IO
上面的对象是公开派生自OVERLAPPED
:
struct IO : public OVERLAPPED
{
char* buf_;
DWORD buf_size_;
DWORD read_;
ThreadParam* thread_;
HANDLE file_;
};
当重叠读取函数完成时,我读取传入的数据并生成一个字符串:
void CALLBACK OnFileRead(DWORD err, DWORD bytes, OVERLAPPED* ovr)
{
IO* io = static_cast<IO*>(ovr);
string msg(io->buf_, bytes);
}
Sender
一无所知Receiver
,并且它使用非常简单但非缓冲的方式将文本发送到控制台。
问题:我知道Sender
正在将数据发送到其 STDOUT,但是我的OnFileRead
函数仅被调用一次,并且仅传输零字节。
为什么我收不到Sender
的输出是这样的吗?我有错误吗,还是我做错了什么?