how to interrupt a thread which is waiting on recv

2020-04-03 08:21发布

I have a socket listener which hangs on recv function:

size_t recvLen = recv(sock, buf, 512, 0);

I would like to terminate this thread with interrupting it. MSDN says:

When issuing a blocking Winsock call such as recv, Winsock may need to wait for a network event before the call can complete. Winsock performs an alertable wait in this situation, which can be interrupted by an asynchronous procedure call (APC) scheduled on the same thread.

How can I do that?

标签: c++ sockets
6条回答
家丑人穷心不美
2楼-- · 2020-04-03 08:23

You can interrupt it by queuing an APC to it via QueueUserAPC. However, it's most likely unsafe to terminate the thread in the APC. Queuing an APC doesn't end the recv, it just interrupts it; once the APC returns, it will go back to waiting on recv again.

If you want to stop the recv completely, you should be using select with a timeout to wait until data is available. You can then check whether you should keep waiting for data or continue at each timeout.

查看更多
倾城 Initia
3楼-- · 2020-04-03 08:23

I think the best way to handle this problem is to put the socket into non-blocking I/O mode, so that the thread will never block inside recv() (or in send(), for that matter). The thread should only ever block inside select() (or WaitMultipleObjects()). That way the select() (or WaitMultipleObjects()) call will return if data arrives for the socket (in which case you can then call recv() to get the new data without blocking), but you can also have select()/WaitMultipleObjects() return when something else happens; e.g. when it gets a prompt from the main thread. If you are using select(), that prompt can be the main thread sending a byte on a different socket-pair (with the main thread holding one end of the socket-pair, and the I/O thread holding the other end); if you are using WaitMultipleObjects() then I believe you can use any of the standard Windows event/signaling methods that would cause WaitMultipleObjects() to return.

查看更多
小情绪 Triste *
4楼-- · 2020-04-03 08:29

If you don't want to receive any more data, you can kill the socket at anytime. Just call close() on it, the function in question will immediately return an error.

What I've done in the past is just run another thread with a timeout, after the waiting period if a "don't die" flag isn't set kill the socket.

查看更多
我想做一个坏孩纸
5楼-- · 2020-04-03 08:38

Errrr... Perform an APC on the same thread? :-))

Seriously, though, it's not clear what your objective here is.
If you just want to end the thread, use the TerminateThread function.
If you want to interrupt this particular call, you can close the socket.

查看更多
一纸荒年 Trace。
6楼-- · 2020-04-03 08:47

The only way to really interrupt a blocking recv() call and make it fully exit is to close the socket from another thread context than the one that is blocked. If that is not an option, then you need to re-write your socket logic. Best to use non-blocking or asynchronous I/O, that way recv() (or WSARecv() for the latter) will never block, and you can do whatever you need to do (like checking for thread termination conditions) while the reading is performed in the background.

查看更多
倾城 Initia
7楼-- · 2020-04-03 08:49

Checking the socket buffer prior to recv is more flexible rather than covering a lot for select() support, I think. You can call ioctlsocket(SockHandle, FIONREAD, Longint(CountInBuffer)) to see if there's data in network buffer to read and then call recv(SockHandle, buff, CountInBuffer, 0). This way you can make a single recv call to read the whole network read buffer if you allocate the buff itself enough with CountInBuffer. Otherwise, you need to call recv in a loop to read the network buffer, which is the traditional way. In both cases, you're still in the constraints of the CountInBuffer.

查看更多
登录 后发表回答