HasOverlappedIoCompleted()
不适用于以ReadFileEx()
和WriteFileEx()
开头的异步I / O.底部的代码片段演示了这一点。在此示例中,ReadFileEx()
从没有输入的管道读取,因此读取将无法完成。但HasOverlappedIoCompleted()
返回TRUE。如果我将调用更改为重叠的ReadFile()
,则HasOverlappedIoCompleted()
会按预期返回FALSE。
我的问题是:如何在不依赖回调本身的情况下找出带回调的重叠I / O请求是否已完成?在我的应用程序中,APC可能已经排队,但不一定必须已经运行,因为应用程序可能还没有等待处于警报状态。
感谢。
(注意GetOverlappedResult()没有帮助 - 它也返回TRUE。)
更多背景:在示例中我使用ReadFileEx()
,因为很容易证明问题。在我的应用程序中,我在管道实例上反复调用WriteFileEx()
。如果之前的WriteFileEx()
尚未完成,则必须删除消息而不是发送消息(我必须在同一个管道实例上没有多个挂起写入),但是如果是前一个{ {1}} 已经完成,然后我必须启动下一个,即使完成回调尚未运行。
编辑:问题情景说明
我想从操作系统中找出WriteFileEx()是否已实际完成,而不是测试我的自定义'write pending'标志,即使APC尚未运行。
WriteFileEx()
答案 0 :(得分:1)
你要求的行为对我来说似乎不对,因为它涉及竞争条件。只有在您仍在发送消息B时收到消息A时才会出现此问题。目前,A始终被忽略,即不会发送其他消息。当且仅当服务器在A到达和B完成之间的间隔期间忙于处理工作时,您尝试获取的行为将导致发送附加消息。我认为你应该总是忽略A或者在B完成后总是发送响应。
但是,如果您确定它是您想要的,则可以获得此行为。一种解决方案是从ReadFileEx完成例程调用QueueUserAPC,将调用排队到发送回复的函数。由于APC以FIFO顺序运行,因此新的APC肯定会在WriteFileEx已经排队的APC之后运行。
根据细节的不同,完成例程设置标志或将项目添加到队列,让主循环完成实际工作可能更清晰。
如果您需要轮询APC(例如,因为您的主循环没有任何自然发生的等待操作),您可以在超时为0的虚拟事件上使用WaitForSingleObjectEx。事件是否无关紧要是否发出信号,仍会调用所有排队的APC。
答案 1 :(得分:1)
我已经改变了你的代码以实现CALLBACK。 要使此示例起作用,管道缓冲区长度不应为0。 另外,我认为管道的两端都应该设置OVERLAPPED标志。
#include <Windows.h>
#include <stdio.h>
#include <assert.h>
#define BUFFSIZE 100
#define MYPIPE "\\\\.\\pipe\\testpipe"
typedef struct {
OVERLAPPED serverOvlp; // Overlapped should always be first in structure
CHAR buffer[20];
} OVLP;
VOID CALLBACK readComplete(DWORD err, DWORD bytes, LPOVERLAPPED ovlp)
{
OVLP *temp = (OVLP *) ovlp;
printf("readComplete err=%d bytes=%d buffer=%s\n", err, bytes, temp->buffer);
}
int main(void)
{
HANDLE hServer;
HANDLE hClient;
OVLP oServer;
DWORD bytes;
CHAR ClientBuffer[20] = "Test message";
hServer = CreateNamedPipe(MYPIPE, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, BUFFSIZE, BUFFSIZE, 5000, NULL);
//-------------------------------------- CLIENT
hClient = CreateFile(MYPIPE, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
WriteFile(hClient,ClientBuffer,strlen(ClientBuffer)+1,&bytes,NULL);
//-------------------------------------- SERVER
ConnectNamedPipe(hServer, &oServer.serverOvlp);
if (HasOverlappedIoCompleted(&oServer.serverOvlp)) assert(GetLastError() != 0 );
puts("Client Pipe connected\n");
ReadFileEx(hServer, oServer.buffer, sizeof(oServer.buffer), (LPOVERLAPPED)&oServer, readComplete);
SleepEx(INFINITE,TRUE); // Creates an alertable event so CALLBACK is triggered
if (HasOverlappedIoCompleted(&oServer.serverOvlp)) {
puts("Completed");
} else {
puts("Not completed");
}
return EXIT_SUCCESS;
}