How to cleanly interrupt a thread lock when calling recv?

I have a multithreaded server written in C, with each client stream looking something like this:

ssize_t n; struct request request; // Main loop: receive requests from the client and send responses. while(running && (n = recv(sockfd, &request, sizeof(request), 0)) == sizeof(request)) { // Process request and send response. } if(n == -1) perror("Error receiving request from client"); else if(n != sizeof(act)) fprintf(stderr, "Error receiving request from client: Incomplete data\n"); // Clean-up code. 

At some point, the client meets certain criteria where it should be disconnected. If the client regularly sends requests, this is normal, because it may be informed that responses are disabled; However, sometimes clients take a long time to send a request, so client flows are blocked in the recv call, and the client does not disconnect until the next request / response.

Is there a clean way to disconnect a client from another thread while the client thread is blocking in a recv call? I tried close(sockfd) , but this caused an Error receiving request from client: Bad file descriptor error, which is really inaccurate.

Alternatively, is there a better way for me to handle errors here?

+8
source share
3 answers

So you have at least these possibilities:

(1) pthread_kill will push the thread out of recv with errno == EINTR, and you can clear and exit the thread yourself. Some people think this is nasty. It really does.

(2) Do not block client sockets and use select to wait at the input for a certain period of time before checking to see if there was a switch used between threads set to disconnect.

(3) In combination with (2), each thread is divided by a pipe with the main thread. Add it to select . If it becomes readable and contains a shutdonw request, the stream is turned off.

(4) Look at the pthread_cancel mechanism if none of the above (or its variants) meets your needs.

+9
source

Turn off the socket to enter from another stream. This will cause the read stream to receive EOS, which should lead to its closure and termination if it is correctly written.

+3
source

To interrupt a thread, make the socket non-blocking (set O_NONBLOCK with fcntl ) and then O_NONBLOCK thread with pthread_kill . Thus, recv will fail with either EINTR if it was sleeping, or EAGAIN or EWOULDBLOCK if it was not (also, it is possible if SA_RESTART is valid, did not check). Note that the socket should not and should not be non-blocking before that. (And, of course, the signal must be processed; an empty handler is enough).

To be sure that you understand the stop signal, but no more, use the flag; There are things that can go wrong. For example, recv may not work with EINTR for any spurious signal. Or it can be successful if there is some data available, effectively ignoring the stop request.

And what not to do

  1. Do not use pthread_kill alone or with any simple check. It may come right before sending the recv call, too early to interrupt it, but after all the checks.

  2. Do not close outlet. This may not even work, and if the @R .. pointer is dangerous, since the socket file descriptor can be reused between close and recv (unless you are sure that nothing opens the file descriptors).

0
source

Source: https://habr.com/ru/post/950128/


All Articles