Reputation: 17467
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
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
Reputation: 310866
Either:
setsockopt()
and SO_RCVTIMEO
, and whenever it triggers check a state variable to see if you've told yourself to stop reading.shutdown(sd, SHUT_RD)
. This will cause recv()
to return zero from now on.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
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
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
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
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
Reputation: 172398
You can call:-
shutdown(sock, SHUT_RDWR) //on the remote end
Check this out.
Upvotes: 5