Reputation: 51
In our server code we are using poll() system call for monitoring client sockets. The poll() is called with a large timeout value. So the thread calling poll() gets blocked for I/O.
As per the flow, we have a scenario where we need to terminate thread that blocked in poll() from a different thread. I have came across pthread_kill() and pthread_cancel() functions, which can terminate the target thread blocked for I/O.
By reading the man pages, both these functions seems to work fine. Few links on internet suggested that both of these functions are dangerous to use.
Is there any alternative way to terminate the thread blocked for I/O ? If not, which of these functions is recommended to use.
Upvotes: 3
Views: 3383
Reputation: 12337
An easy and clean option is to create a "signal" pipe. That is, call pipe
, take the file descriptor for the "read" end and add it to your list of poll
file descriptors (with POLLIN
). Then, whenever you want to unblock the thread which is waiting in poll
, just write a byte to the write end of the pipe. The pipe, having received data, will return as readable in the blocked thread. You can even specify different "commands" by varying the value of the byte written.
(You'll need to read the byte from the pipe before it can be re-used of course.)
Upvotes: 3
Reputation: 215193
There is no such thing as killing a thread.
The poorly-named pthread_kill
function is a threads analogue of the poorly-named kill
function, which sends a signal to process. The name kill
historically made sense in that the default action of many signals is to kill the process. But this default action of killing the process does not depend on whether the signal was sent to the process or a particular thread - either way, the process terminates.
The only time pthread_kill
is useful is when you want to invoke a signal handler on another thread. Unless you are certain that the signal handler could not have interrupted any function that is not async-signal-safe, the signal handler is limited to calling functions which are async-signal-safe, and thereby cannot even act to end the thread's lifetime (pthread_exit
is not async-signal-safe).
If you're okay with the thread eventually terminating as a result of the call, pthread_cancel
is the right way to end a thread stuck in a blocking operation. In order to use it safely, though, you need to make heavy use of pthread_cleanup_push
and pthread_cleanup_pop
.
If you don't want the thread to terminate, signals are your only option. You have two choices:
Install a signal handler (can be a no-op) using sigaction
without SA_RESTART
, so that it causes EINTR
. Since there are inherent race conditions in this approach (if you send the signal just before the blocking syscall is entered, rather than once it's blocked, the signal won't do anything) you need to repeatedly send the signal, with exponential back-off so as not to starve the target of execution time, until the target confirms via some other synchronization mechanism (a POSIX semaphore works well) that it got the message.
Install a signal handler that will longjmp
. In order to do this safely you need to control the context from which it can happen; the easiest way to do this is to keep it blocked in the signal mask normally, only unmasking it when the jmp_buf
is valid around a blocking call. The blocking function you call needs to be async-signal-safe, and it needs to not be one which allocates or frees resources (like open
or close
) since you will lose knowledge of whether it completed when you handle the signal. Of course the jmp_buf
, or a pointer to it, needs to be a thread-local object (_Thread_local
/__thread
) in order for this to work at all.
Upvotes: 2
Reputation: 6063
Depending on the exact implementation of your thread library, it's very likely the thread won't even return from poll
when being killed - so, you probably won't even achieve what you want.
You need to be very careful not to create memory leaks, and still are very likely to create a file descriptor leak by killing the thread that owns it (note, thread resources, in contrary to processes, aren't "cleaned up" by the system).
It is generally safer to use shorter timeout periods and poll a terminate flag in-between, or use signals to interrupt the system call, then terminate the thread under its own control, freeing all allocated resources.
Upvotes: 2