2

プログラムがフリーズしている理由を突き止めようとしていますが、GetQueuedCompletionStatus() に絞り込みました。

すべての IOCP スレッドが凍結され、スレッドが持つ唯一のブロッキング呼び出しは GetQueuedCompletionStatus() です。

関連付けられたソケットに接続している顧客がまだいる場合でも、約 30 分 ~ 6 時間の実行時間後に GetQueuedCompletionStatus() が永久にブロックし続ける理由はありますか?

これは IOCP を使用する TCP Winsock プログラムです。OSはWindows Server 2008 R2 Enterpriseです。

ありがとう。

スレッド コード:

    while (TRUE)
    {
        pClient = NULL;
        pOverlapped = NULL;
        bRet = GetQueuedCompletionStatus(hCompletionPort, &dwIOLen, (LPDWORD)&pClient, (LPOVERLAPPED*)&pOverlapped, INFINITE);
        if (bRet == true && pClient != NULL && pOverlapped != NULL && pClient->bConnected == true && pClient->bToDisconnect == false)
        {
            if (pOverlapped->bIOMode == 0) // Recv
            {
                if (TryEnterCriticalSection(&pClient->mNetworkReadCSection))
                {
                    pClient->dwSockBuffLength += dwIOLen;

                    // Packet processing here...

                    WSABUF pWSABuf;
                    pWSABuf.buf = (char*)&pClient->mSockBuffer[pClient->dwSockBuffLength];
                    pWSABuf.len = 10000 - pClient->dwSockBuffLength;
                    DWORD dwRecvd;
                    DWORD dwFlags = 0;
                    memset(&pClient->mSockOverlapped, 0x00, sizeof(WSAOVERLAPPED));
                    pClient->mSockOverlapped.bIOMode = 0;
                    int iSent = WSARecv(pClient->ClientSocket, &pWSABuf, 1, &dwRecvd, &dwFlags, (WSAOVERLAPPED*)&pClient->mSockOverlapped, NULL);
                    if (iSent == SOCKET_ERROR)
                    {
                        if (WSAGetLastError() == 10053 || WSAGetLastError() == 10054 || WSAGetLastError() == 10058)
                        {
                            //pClient->bToDisconnect = true;
                            //LeaveCriticalSection(&pClient->mNetworkReadCSection);
                            OnDissconnect(pPacketWriter, pClient->iClientID);
                            continue;
                        }

                        if (WSAGetLastError() != 997 &&  WSAGetLastError() != 10004 && WSAGetLastError() != 10038)
                            WriteToFile("IOCPSocketErr.txt", "[%s] Socket Error: %d\n", pClient->szPlayerName, WSAGetLastError());
                    }

                    LeaveCriticalSection(&pClient->mNetworkReadCSection);
                }
                else
                {
                    PostQueuedCompletionStatus(hCompletionPort, dwIOLen, (DWORD)pClient, (OVERLAPPED*)pOverlapped);
                }
            }
            else if (pOverlapped->bIOMode == 1) // Send
            {
                dwBytesSent += dwIOLen;
            }
        }
    }
4

2 に答える 2

2

コードのバグである可能性が最も高いです。

私は IOCPGetQueuedCompletionStatus()を 10 年以上使用してきましたが、どのプラットフォームでも問題が発生したことはありません。

まず、切断の上でコメントアウトするとLeaveCriticalSection(&pClient->mNetworkReadCSection);、このエラーの後、ソケットがロックされたままになります...

個人的には、マジック ナンバーよりもエラー定数が使用されていることを確認することを好みます。ここで「処理」しているエラーを正確に確認するのは困難です。

保留中の I/O 操作がなく、IOCP スレッドでアクティビティがないという状況に陥っていると思います。I/O 操作を発行するときにインクリメントし、完了時にデクリメントするデバッグ目的でカウンターを維持できます。また、独自の完了をポートに投稿するときにもインクリメントします。これは、ハングしたプログラムに侵入したときに保留中の I/O 操作があるかどうかを確認するのに役立ちます。操作を発行する前にカウンターをインクリメントする (操作が失敗した場合はデクリメントする) ことを忘れないでください。

于 2012-10-11T07:19:04.297 に答える
0

ドキュメントを正しく読むと、GetQueuedCompletionStatus が false を返し、pOverlapped が NULL でない場合があります。おそらく、このケースをテストして処理する必要があります。

于 2013-04-09T14:38:10.127 に答える