gpt4 book ai didi

c++ - ReadFileEx,可变长度——几个问题

转载 作者:行者123 更新时间:2023-11-28 02:44:26 25 4
gpt4 key购买 nike

我正在尝试从子进程的 stderr 中读取。数据是使用 sprintf(stderr, "some debug info\n") 创建的文本行。我将 ReadFileEx 与完成例程一起使用。我不知道有多少行文本或每行有多长。那么,我应该将什么作为 nNumberOfBytesToRead 参数?

我的猜测是我将缓冲区的最大大小设置为 4k;虽然我不知道这是否是最佳尺寸。我猜测如果写入 stderr 的行短于 4k,则不会触发完成例程。我猜测当达到 4k 但仍有更多数据时,我必须在完成例程中触发另一个 ReadFileEx。我知道是这种情况,因为 GetLastError 将返回 ERROR_MORE_DATA。我希望在缓冲区未满但子进程已退出时接到电话。我不确定子进程退出时我是否得到完成回调,因为我在创建子进程时将 stderr 写句柄传递给了它;也许我在 关闭该句柄时收到回调。当 child 对我的阅读 stderr 关闭 wrt 时是否存在任何竞争条件?

下面是如何创建进程和句柄的伪代码:

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 创建的匿名管道不能异步使用。来自 Windows SDK 文档:

Asynchronous (overlapped) read and write operations are not supported by anonymous pipes. This means that you cannot use the ReadFileEx and WriteFileEx functions with anonymous pipes. >In addition, the lpOverlapped parameter of ReadFile and WriteFile is ignored when these >functions are used with anonymous pipes.

基本上 CreatePipe 不接受 FILE_FLAG_OVERLAPPED 标志,异步 I/O 要求您在创建文件句柄时使用该标志。

您必须使用 CreateNamedPipe 来创建命名管道。问题Overlapped I/O on anonymous pipe有一个链接到您可以使用的替换函数 MyCreatePipeEx 的答案。

在尝试从另一端已关闭的管道读取后,您的完成端口应该会收到一个零长度读取事件。

要从客户端进程读取可变数量的数据,只需发出您认为方便的任何大小的读取请求,并准备好处理比您请求的更短的读取事件。不要将短但非零的长度解释为 EOF。继续发出读取请求,直到读取长度为零或出现错误。

此外,WaitForMultipleObjects 不会与完成例程一起使用,因为它们仅在线程处于 alterable state 中时被调用。 .使用 WaitForMultipleObjectEx 并将 bAlertable 参数设置为 true。此函数将在运行一个或多个完成例程后返回 WAIT_IO_COMPLETION。在这种情况下,您可能希望立即再次调用 WaitForMultipleObjectEx

关于c++ - ReadFileEx,可变长度——几个问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24916823/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com