Nan Xiao
Nan Xiao

Reputation: 17467

How to let a thread which blocks on recv() exit gracefully?

There is a thread likes this:

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

Because the thread is blocking on recv() call, how can I let the thread exit gracefully?

Upvotes: 9

Views: 8180

Answers (7)

alk
alk

Reputation: 70901

Declare a global exit flag:

int bExit = 0;

Let the cirtical parts test it:

 while(1)
 {
   ssize_t result = recv(socket, buffer, sizeof(buffer), 0);
   if ((-1 == result) && (EINTR == error) && bExit) 
   {
     break;
   }

   ...
 }

To break your reader, first set the exit flag

bExit = 1;

then send a signal to the reader thread

pthread_kill(pthreadReader, SIGUSR1);

Note: What I left out in this example is the protection of bExit against concurrent access.

This might be achieved by using a mutex or an appropriate declaration.

Upvotes: 2

user207421
user207421

Reputation: 310866

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.

Upvotes: 4

pilcrow
pilcrow

Reputation: 58534

I would likely use signals as in @alk's fine answer (also discussed here).

Alternatively, you may use multiplexed I/O.

At initialization, create a global pipe(2). When it is time to end the program, close the write-end of the pipe — now the read-end will instantly select(2)/poll(2) readable (for EOF). Meanwhile, have your recv-blocked threads include the read-end of this pipe along with their sockets in, for example, an indefinitely blocking select(2) call. If the read-end of the pipe returns readable, the I/O threads know it is time to terminate gracefully.

The major caveat of this technique is to ensure that the write-end is closed only once, as a subsequent, naïve close(2) might nip some innocent file that happens to have been given the same descriptor as the pipe's old write-end.

Upvotes: 2

Martin James
Martin James

Reputation: 24847

Declare some 'stop' boolean, check it after every recv() return and terminate if it's set. To shut down, set the bool and close the socket from another thread. The blocking recv() will return 'immediately' with an error, but it does not matter 'cos you're about to terminate anyway:)

Upvotes: 2

gwilkins
gwilkins

Reputation: 546

Also, set your socket to be nonblocking:

int listen_sd = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (listen_sd < 0) {
    perror("socket() failed");
}

int on = 1;

//set socket to be non-blocking
int rc = ioctl(listen_sd, FIONBIO,(char *)&on);
if (rc < 0) {
    perror("ioctl() failed");
    close(listen_sd);
}

Then, you can call recv() on the socket, and it won't block. If there's nothing to read then the ERRNO global variable is set to the constant EWOULDBLOCK

int rc = recv(listen_sd, buffer, sizeof(buffer), 0);
if (rc < 0) {
    if (errno != EWOULDBLOCK) {
        perror("recv() failed");
    }
}

Upvotes: 0

Sass
Sass

Reputation: 560

Do not block on recv. Rather implement a block on 'select' and test the input fdset to determine if there is anything to read in the first place.

If there is data to be read, call recv. If not, loop, check 'isrunning' volitile Boolean variable that gets set by the other thread when shutdown has been initiated.

Upvotes: 5

Rahul Tripathi
Rahul Tripathi

Reputation: 172398

You can call:-

shutdown(sock, SHUT_RDWR)    //on the remote end

Check this out.

Upvotes: 5

Related Questions