ReadFile(socket) 被取消,如果调用它的线程死亡

Posted

技术标签:

【中文标题】ReadFile(socket) 被取消,如果调用它的线程死亡【英文标题】:ReadFile(socket) is cancelled, if the thread that called it dies 【发布时间】:2013-09-01 12:38:36 【问题描述】:

我正在尝试学习异步 I/O。 我的程序创建套接字并使用 AcceptEx 接受它们或使用 connect 连接它们。在其主线程中,我在循环中调用 WaitForMultipleObjects(),但我仍然创建线程来解析名称,调用 connect() 并调用初始 ReadFile()。 这些线程在调用 ReadFile() 后退出,让主线程等待读取结果。

由于某种原因,连接线程终止后,读取操作被取消,事件被触发,GetOverlappedResult() 失败并出现 ERROR_OPERATION_ABORTED

例子:

#define _WIN32_WINNT 0x0501

#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#include <windows.h>

#include <stdio.h>
#include <tchar.h>


#define BUFSZ 2048

#define PORT 80
#define HOST "192.168.2.1"
#define HOST "***.com"

static struct 
    char buf[BUFSZ];
    OVERLAPPED overlap;
    SOCKET sock;
 x =  0 ;

static DWORD WINAPI barthread(LPVOID param) 
    static struct sockaddr_in inaddr =  0 ;
    int rc;
    BOOL b;
    DWORD dw;
    DWORD nb;
    LPHOSTENT lphost;

    x.sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    inaddr.sin_family = AF_INET;

    lphost = gethostbyname(HOST);
    inaddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
    inaddr.sin_port = htons(PORT);

    rc = connect(x.sock, (struct sockaddr *)&inaddr, sizeof(struct sockaddr_in));

    if (rc == 0) 
        printf("thread 2 connected\n");
        printf("thread 2 call ReadFile\n");
        b = ReadFile((HANDLE)x.sock, x.buf, BUFSZ, &nb, &x.overlap);
        dw = GetLastError();
        if (b || dw == ERROR_IO_PENDING) 
            printf("thread 2 ReadFile ok\n");
         else 
            printf("thread 2 ReadFile failed\n");
        
        printf("thread 2 sleeping\n");
        Sleep(3000);
        printf("thread 2 dying\n");
    
    return 0;


int main(int argc, char* argv[])

    WSADATA WD;

    BOOL b;
    DWORD dw;
    DWORD nb;
    DWORD tid;

    WSAStartup(MAKEWORD(2, 0), &WD);

    x.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    CreateThread(NULL, 0, barthread, NULL, 0, &tid);

    dw = WaitForSingleObject(x.overlap.hEvent, INFINITE);
    printf("thread 1 event triggered\n");
    b = GetOverlappedResult((HANDLE)x.sock, &x.overlap, &nb, FALSE);
    dw = GetLastError();
    printf("thread 1 GetOverlappedResult() = %d, GetLastError() = %d\n", b, dw);

    return 0;

【问题讨论】:

这样的日志没有看到创建它的实际代码是没有用的。请出示实际代码。 @Remy 缩短了我的程序 【参考方案1】:

您根本不应该使用单独的线程。重叠 I/O 的全部意义在于单个线程可以同时执行多个任务。让您的主循环使用WSAAsyncGetHostByName() 而不是gethostbyname(),并在非阻塞模式下使用WSAConnect(),在阻塞模式下使用WSAEventSelect() 而不是connect()

【讨论】:

我已阅读有关 WSAAsyncGetHostByName 的信息。 ***.com/questions/1726181/… : "WSAAsyncGetHostByName 甚至不允许并发名称解析" "出于某种原因被设计用于处理窗口消息,而不是重叠操作" 在这种情况下您仍然可以使用它。主循环可以包含一个用于接收异步查找的隐藏窗口,并使用MsgWaitForMultipleObjects() 处理这些消息,同时等待其他对象。【参考方案2】:

在这里找到了类似的问题: Asynchronous socket reading: the initiating thread must not be exited - what to do? 并且,在这里:http://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/reference/asynchronous_operations.html:

具体来说,在 Vista 之前的 Windows 版本中,未完成的操作会在启动线程退出时被取消。

我有 Windows 7,但遇到同样的问题。

我不会在临时线程中调用初始 ReadFile(),而是设置一些标志,手动设置事件并在主循环中调用 ReadFile()。

【讨论】:

以上是关于ReadFile(socket) 被取消,如果调用它的线程死亡的主要内容,如果未能解决你的问题,请参考以下文章

如何找出 CancelIo() 何时完成?

取消意图未调用 Alexa

socket通讯IOCP模型

Socket编程中,阻塞与非阻塞的区别

如何等待多个 fs.readFile 调用?

在 LockFileEx 之后调用 ReadFile 时崩溃