为什么我打算在取消接受操作后打电话给GetoverLappedResult悬挂?

问题描述 投票:0回答:1
我有一个线程,该线程在听力端口上反复调用

AcceptEx

直到被告知退出为止,此时它将试图取消最后的启动接受。
注:要澄清,如果第一个参数隐含转换为

TASSERT

(如果不转换为布尔值),则

TASSERTF
false
宏中止该过程 我这样做的代码看起来像
        // Cancel the last initiated accept (if it's still in progress)
        if (!::CancelIoEx((HANDLE)g_unpipeListenSocket, &overlapped)) {
            const DWORD error(::GetLastError());

            // This should _never_ fail
            TASSERTF(ERROR_NOT_FOUND == error, "CancelIoEx() failed: %s", Win32ErrorToString(error).c_str());
        }
        else {
            // The accept was still in progress, wait until it's complete
            DWORD unused;
            TASSERTF(
                ::GetOverlappedResult((HANDLE)g_unpipeListenSocket, &overlapped, &unused, TRUE),
                "GetOverlappedResult() failed: %s",
                Win32ErrorToString(::GetLastError()).c_str());
        }

        sock_close(acceptingSocket);
        sock_close(g_unpipeListenSocket);

所以发生了什么是成功,但随后呼唤

CancelIoEx
只是永远悬而未决。
我的理解是,仅关闭插座并允许

GetOverlappedResult

被划分(因为它在线程的堆栈上即将返回)将使门打开以获得无用的无用,因为这不足以取消取消正在进行的I/O操作(或至少不足以等待取消生效)
任何一次,只有一次接受操作;这是我用来启动它们并处理其相关完成的代码:

overlapped

i我在线程开头时一次调用一次,然后每次我完成以前的接受的完成。如果我的错误处理代码是问题:

g_unpipeListenSocket

	

看起来这个问题是我正在使用
static void
BeginAccept(SOCKET& io_acceptingSocket, OVERLAPPED& in_overlapped, AcceptExBuff& in_acceptExBuff) noexcept {
    memset(&in_overlapped, 0, sizeof(in_overlapped));

    if (INVALID_SOCKET == io_acceptingSocket) {
        io_acceptingSocket = sockit(g_unpipeInAddr.inx_family, SOCK_STREAM, IPPROTO_TCP);
        if (INVALID_SOCKET == io_acceptingSocket) {
            char errorString[MAX_SOCK_ERROR_LEN];
            sock_error_string(getSockErr(), errorString);

            // TODO: Don't abort (exit thread & notify waiters somehow so they can start it again next time?)
            TABORT("sockit() failed: %s", errorString);
        }
    }

    DWORD bytesReceived;
    TASSERTF(!AcceptEx(
        g_unpipeListenSocket,
        io_acceptingSocket,
        &in_acceptExBuff,
        0,
        sizeof(in_acceptExBuff) / 2,
        sizeof(in_acceptExBuff) / 2,
        &bytesReceived,
        &in_overlapped),
        "AcceptEx() completed synchronously?");

    const DWORD error(::WSAGetLastError());

    // TODO: Don't abort (exit thread & notify waiters somehow so they can start it again next time?)
    TASSERTF(
        ERROR_IO_PENDING == error,
        "AcceptEx() failed synchronously: (%u) %s",
        error,
        Win32ErrorToString(error).c_str());
}

static void
HandleAccept(
    SOCKET& io_acceptingSocket,
    OVERLAPPED& in_overlapped,
    AcceptExBuff& in_acceptExBuff) noexcept {
    TASSERT(io_acceptingSocket != INVALID_SOCKET);

    const SOCKET connectedSocket(io_acceptingSocket);
    io_acceptingSocket = INVALID_SOCKET;

    // Begin the next accept...
    BeginAccept(io_acceptingSocket, in_overlapped, in_acceptExBuff);

    // Finish setting up accepted socket.
    // TODO: Don't abort (exit thread & notify waiters somehow so they can start it again next time?)
    TASSERTF(
        !::setsockopt(connectedSocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (PCHAR)&g_unpipeListenSocket, sizeof(SOCKET)),
        "setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed:");

    // Consume the connected socket
}
而不是

BeginAccept

;当我切换到后者时(并将事件设置为我使用的
HandleAccept
结构的句柄,因为记录了通过
GetQueuedCompletionStatus
),事情开始工作了。
我当前的线程清理时的当前代码看起来像

if (!::GetQueuedCompletionStatus(
            g_unpipeListenThreadIOCP,
            &numBytes,
            &completionKey,
            &overlappedPtr,
            INFINITE))
        {
            const DWORD error(::GetLastError());

            TASSERTF(
                (&overlapped == overlappedPtr) && (ACCEPT_THREAD_ACCEPT_COMPLETION_KEY == completionKey),
                "&overlapped=%p overlappedPtr=%p completionKey=%" FSIZE "u GetLastError()='%s'",
                &overlapped,
                overlappedPtr,
                completionKey,
                Win32ErrorToString(error).c_str());
            SIMBA_TRACE(
                "Retrieved completion status about error on accept operation: %s",
                Win32ErrorToString(error).c_str());

            // Start another accept (Should we consider this a fatal error?)
            BeginAccept(acceptingSocket, overlapped, acceptExBuff);

            continue;
        }
winapi winsock io-completion-ports
1个回答
0
投票

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.