How to cleanly interrupt a thread blocking on a recv call?

c, multithreading, posix, pthreads, sockets

Solution

So you have at least these possibilities:

(1) `pthread_kill` will blow the thread out of `recv` with errno == EINTR and you can clean up and exit the thread on your own. Some people think this is nasty. Depends, really.

(2) Make your client socket(s) non-blocking and use `select` to wait on input for a specific period of time before checking if a switch used between the threads has been set to indicated they should shut down.

(3) In combo with (2) have each thread share a pipe with the master thread. Add it to the `select`. If it becomes readable and contains a shutdonw request, the thread shuts itself down.

(4) Look into the `pthread_cancel` mechanism if none of the above (or variations thereof) do not meet your needs.

Problem

I have a multithreaded server written in C, with each client thread 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, a client meets a certain criteria where it must be disconnected. If the client is regularly sending requests, this is fine because it can be informed of the disconnection in the responses; However sometimes the clients take a long time to send a request, so the client threads end up blocking in the `recv` call, and the client does not get disconnected until the next request/response. Is there a clean way to disconnect the client from another thread while the client thread is blocking in the `recv` call? I tried `close(sockfd)` but that causes the error `Error receiving request from client: Bad file descriptor` to occur, which really isn't accurate. Alternatively, is there a better way for me to be handling errors here?

Original source

Related problems