0

I'm trying to learn async I/O.
My program creates sockets and either accepts them with AcceptEx or connects them with connect. In its main thread I call WaitForMultipleObjects() in a loop, but I still create threads to resolve the names, call connect() and call the initial ReadFile().
These threads exit after they call ReadFile() and let the main thread wait for the read result.

For some reason, after the connecting thread dies, the read operation is cancelled, the event is triggered and GetOverlappedResult() fails with ERROR_OPERATION_ABORTED

Example:

#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 "stackoverflow.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;
}
basin
  • 3,949
  • 2
  • 27
  • 63

2 Answers2

2

You shouldn't be using separate threads at all. The whole point of overlapped I/O is that a single thread can do multiple tasks at one time. Have your main loop use WSAAsyncGetHostByName() instead of gethostbyname(), and WSAConnect() in non-blocking mode with WSAEventSelect() instead of connect() in blocking mode.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I've read about WSAAsyncGetHostByName. http://stackoverflow.com/questions/1726181/asynchronous-address-resolution-in-winsock : "WSAAsyncGetHostByName doesn't even allow concurrent name resolution" – basin Sep 02 '13 at 06:44
  • "is designed for some reason to work with window messages, instead of overlapped operations" – basin Sep 02 '13 at 06:45
  • You can still use it in this situation. The main loop can contain a hidden window for receiving async lookups, and use `MsgWaitForMultipleObjects()` to process those messages while waiting on other objects at the same time. – Remy Lebeau Sep 02 '13 at 17:09
0

Found the similar question here: Asynchronous socket reading: the initiating thread must not be exited - what to do?
and, here: http://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/reference/asynchronous_operations.html :

Specifically, on Windows versions prior to Vista, unfinished operations are cancelled when the initiating thread exits.

I have Windows 7, but suffer from the same problem.

Instead of calling the initial ReadFile() in a temporary thread I will just set some flag, set the event manually and call ReadFile() in the main loop.

Community
  • 1
  • 1
basin
  • 3,949
  • 2
  • 27
  • 63