Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ GetQueuedCompletionStatus可以';如果最初发出IO的线程在windows 8下的ReadFile中阻塞,则从IOCP中退出IO_C++_Sockets_Windows 8_Winsock_Iocp - Fatal编程技术网

C++ GetQueuedCompletionStatus可以';如果最初发出IO的线程在windows 8下的ReadFile中阻塞,则从IOCP中退出IO

C++ GetQueuedCompletionStatus可以';如果最初发出IO的线程在windows 8下的ReadFile中阻塞,则从IOCP中退出IO,c++,sockets,windows-8,winsock,iocp,C++,Sockets,Windows 8,Winsock,Iocp,切换到windows 8后,我的应用程序停止工作。我花了几个小时调试这个问题,发现IOCP在Windows8和以前的版本之间表现不同。我提取必要的代码来演示和再现问题 SOCKET sListen; DWORD WINAPI WorkerProc(LPVOID lpParam) { ULONG_PTR dwKey; DWORD dwTrans; LPOVERLAPPED lpol; while(true) { GetQueuedCompl

切换到windows 8后,我的应用程序停止工作。我花了几个小时调试这个问题,发现IOCP在Windows8和以前的版本之间表现不同。我提取必要的代码来演示和再现问题

SOCKET sListen;

DWORD WINAPI WorkerProc(LPVOID lpParam)
{
    ULONG_PTR dwKey;
    DWORD dwTrans;
    LPOVERLAPPED lpol;
    while(true)
    {
        GetQueuedCompletionStatus((HANDLE)lpParam, &dwTrans, &dwKey, (LPOVERLAPPED*)&lpol, WSA_INFINITE);
        printf("dequeued an IO\n");
    }
}
DWORD WINAPI StartProc(LPVOID lpParam)
{
    WSADATA WsaData;
    if (WSAStartup(0x202,&WsaData)!=0) return 1;
    sListen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
    SOCKADDR_IN si;
    ZeroMemory(&si,sizeof(si));
    si.sin_family = AF_INET;
    si.sin_port = ntohs(1999);
    si.sin_addr.S_un.S_addr = INADDR_ANY;
    if(bind(sListen, (sockaddr*)&si, sizeof(si)) == SOCKET_ERROR) return 1;
    listen(sListen, SOMAXCONN);
    HANDLE hCompletion = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
    CreateIoCompletionPort((HANDLE)sListen, hCompletion, (DWORD)0, 0);
    CreateThread(NULL, 0, WorkerProc, hCompletion, 0, NULL);
    return 0;
}
DWORD WINAPI AcceptProc(LPVOID lpParam)
{
    DWORD dwBytes;
    LPOVERLAPPED pol=(LPOVERLAPPED)malloc(sizeof(OVERLAPPED));
    ZeroMemory(pol,sizeof(OVERLAPPED));
    SOCKET sClient = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
    BOOL b = AcceptEx(sListen, 
        sClient,
        malloc ((sizeof(sockaddr_in) + 16) * 2), 
        0,
        sizeof(sockaddr_in) + 16, 
        sizeof(sockaddr_in) + 16, 
        &dwBytes, 
        pol);
    if(!b && WSAGetLastError() != WSA_IO_PENDING)   return 1;
    HANDLE hPipe=CreateNamedPipeA("\\\\.\\pipe\\testpipe",PIPE_ACCESS_DUPLEX,PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,PIPE_UNLIMITED_INSTANCES,4096,4096,999999999,NULL);
    BYTE chBuf[1024]; 
    DWORD  cbRead; 
    CreateFileA("\\\\.\\pipe\\testpipe", GENERIC_READ |GENERIC_WRITE,  0,NULL, OPEN_EXISTING, 0, NULL);
    ReadFile(hPipe,chBuf,1024, &cbRead,NULL);
    return 0;
}

int main()
{
    printf ("Starting server on port 1999...");
    WaitForSingleObject(CreateThread(NULL, 0, StartProc, NULL, 0, NULL),INFINITE);
    CreateThread(NULL, 0,AcceptProc, NULL, 0, NULL);
    printf ("done\n");
    Sleep(10000000);
    return 0;
}
此程序在端口1999上侦听并发出异步accpet,然后读取阻塞管道。我已经在Windows 7、8、XP、2003、2008上测试了此程序,在“telnet 127.0.0.1 1999”之后,“退出IO队列”将在除Windows 8之外的控制台上打印

关键是最初发出异步操作的线程不得在ReadFile中阻塞,否则GetQueuedCompletionStatus在windows 8上返回ReadFile之前将永远不会退出该IO

我还使用“scanf”而不是readpipe进行了测试,结果是一样的,因为“scanf”最终将调用ReadFile来读取控制台。我不知道ReadFile是否是唯一受影响的函数,或者可能还有其他函数

我能想到的是使用一个专用线程来发出异步操作,所有业务逻辑都与该专用线程通信以执行accept/send/recv。但是额外的层意味着额外的开销,有没有办法在windows 8上实现与以前版本的windows相同的性能?

请参见

这是一个bug,官方的MS回应是:“我们已经把它传递给了基础OS团队,他们会考虑这个问题,为将来的更新做准备。我正在解决这个问题。”


注意:我今天(2013年9月12日)在一个完全修补的Windows 8版本上运行了此测试,为测试Windows 8.1做准备,发现问题似乎已在Windows 8上得到解决。我不知道它是什么时候修复的。

你在2012服务器上试过吗?我可以确认上面的测试程序在2012服务器上也失败了。有趣的是。。。如果使用WSAAcept()以阻塞方式接受,然后在对管道执行阻塞读取之前发出重叠读取,则不会以相同的方式阻塞。重叠读取按预期操作。因此,看起来只是AcceptEx的行为是这样的…调整主代码,使其等待5秒,然后终止accept线程,这将导致处理AcceptEx完成数据包(假设您已连接)。因此,这似乎是由于线程在ReadFile中被阻塞的事实……我已经在这里交叉发布了这个消息:因为我认为这非常重要!至少你从他们那里得到了某种回应:)是的,没有我希望的那么有用。如果能指出问题发生的原因以及哪些API可能会导致问题,那就太好了。MS Connect没有希望了,但不幸的是,这是向Microsoft报告此类情况的唯一方法。例如,上次我在WCF中报告一个bug时,它落入了一个繁文缛节的陷阱,至今仍未修复。我想这个AcceptEx bug稍微重要一点,尽管它会影响核心操作系统。我仍然认为您将等待大约6个月。我怀疑它会影响IIS或SQL Server(或者它会在RTM之前被发现),所以我同意,我预计需要一段时间才能修复。它不太可能影响我的客户,了解它(以及相关问题的可能性)应该有助于人们发现它,并在可能的情况下解决它。我当然希望它比其他报告更有吸引力。他们在VS2010中的regex impl在序列接收中被破坏(它实际上使用N-1而不是N作为发生计数)立即报告;他们的回答是:我们在VS2012中修复了它,所以当我们发布它时就切换到那个版本(当时它还在测试版)。Pffft。几英里外都能听到踩踏返回助推器的雷鸣声。