0

I have a thread that contains a blocking recv() call, something like this:

{   
    while(1)
    {
        recv(socket, buffer, sizeof(buffer), 0);
    }       
}

Now what I want to do is to signal the recv() function from another thread to make it exit its blocking state. I have read the following answer from another question that talks about how to do this in Unix (How to let a thread which blocks on recv() exit gracefully?):

Either:

  1. Set a read timeout, with setsockopt() and SO_RCVTIMEO, and whenever it triggers check a state variable to see if you've told yourself to stop reading.
  2. If you want to stop reading the socket forever, shut it down for input with shutdown(sd, SHUT_RD). This will cause recv() to return zero from now on.
  3. Set the socket into non-blocking mode and use select() with a timeout to tell you when to read, adopting the same strategy with a state variable as at (1) above. However non-blocking mode introduces considerable complications into the send operation, so you should prefer (1) or (2) above.

Your pseudo-code lacks EOS- and error-checking. I hope it doesn't really look like that.

I am not interested in the first and third solutions because the CPU will probably get exhausted, and based on my testing, the second solution is not supported in Windows (am I right?). So is there another solution to exit a blocking recv()?

Community
  • 1
  • 1
Trevor
  • 11
  • 2
  • 2
    Option #3 is the one that's used most of the time, and is the most portable one. I have no idea what those mysterious "considerable complications" are. It's fairly cut, and dry. – Sam Varshavchik Aug 13 '16 at 19:12
  • You don't need to set the socket to non-blocking mode when using `select`. Just use `select` with a short timeout (say 200msec). When `select` returns, check the state variable to see if you're supposed to stop. Only call `recv` if the socket has data. – user3386109 Aug 13 '16 at 19:24
  • It is quite nonsense to use a blocking function if you don't want it to block ... – too honest for this site Aug 13 '16 at 19:28
  • @Olaf I do want it to block, I just want to also be able to make it exit its blocking state so that I can terminate the thread when closing my application. – Trevor Aug 13 '16 at 19:31
  • @Trevor: So you apparently don't want it to block! Or did you see some magical "unblock" call in the library? There is a reason these libraries provide the fundamental functionality only. That's why they are called "low-level" libraries. You still don't explain what the actual problem is with `select` etc. (on Linux you can use `poll`/`epoll`, but Windows is - as always not that modern. – too honest for this site Aug 13 '16 at 19:33
  • If you don't care about portability very much, you can use `WSARecv` in overlapped mode. After the call, you can use `WaitForMultipleObjects` to wait for the either completion event, or for a special event that you use to inform the thread that you don't wish to wait any longer. – Martin Drab Aug 13 '16 at 19:34
  • @MartinDrab: And that is a POSIX function? – too honest for this site Aug 13 '16 at 19:34
  • @Olaf But if I used a non-blocking socket, then I would keep looping to see if `recv()` has any data, and even if I used `select()`, I also must use a timeout and keep looping. Also, is there a rule that says that a blocking function can never be allowed to exit its blocking state from another thread? – Trevor Aug 13 '16 at 19:35
  • 1
    Yes, when you use `select`, you must use a timeout and keep looping, but it uses 0% of the CPU (as long as you use a reasonable value for the timeout). Just try it. – user3386109 Aug 13 '16 at 19:40
  • @user3386109 Great to know, thanks :) – Trevor Aug 13 '16 at 19:41
  • @Olaf No, it is not. You did not say you want a POSIX-compatible solution (which would be one with the `select` call). – Martin Drab Aug 14 '16 at 10:30
  • @MartinDrab: I'm not the asker, but " the second solution is not supported in Windows" made me think OP wants a portable solution. Maybe I'm wrong, though – too honest for this site Aug 14 '16 at 13:30
  • @Trevor: Carefull with assumptions. Profile your code **iff** you experience actual problems. – too honest for this site Aug 14 '16 at 13:34

1 Answers1

4

A blocking recv() exits only if:

  1. data is read.

  2. The read times out (SO_RCVTIMEO).

  3. The connection is closed.

If none of those options are viable for you, you will have to simply not call recv() in blocking mode until you know there is something waiting to be read, as reported by select(), WSAAsyncSelect(), or WSAEventSelect().

Otherwise, re-write your socket logic to either:

  1. use the socket in non-blocking mode.

  2. use WSARecv() or RIOReceive/Ex() with Overlapped I/O or an I/O Completion Port. An I/O operation can be canceled with CancelIo/Ex().

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770