I have the following situation:
There is a thread that reads from a device with a fread call. This call is blocking as long as there is no data send from the device.
You really want to read about the select(2)
system call, which will allow you to find out whether there is data available on that file descriptor, without blocking at all or without blocking on only that device.
In the thread, instead of blocking with fread
, block with select
. When select
returns, check an "am I done" variable. If not done, you can call fread
to get the data.
From the other thread -- that wants to stop the fread thread -- you can set the "am I done" variable and then close the fd so that the fread thread will wake up from select
immediately.
If your context prohibits you from closing the fd (you mention you're reading from a device, but say you had a socket you wanted kept open), you could open a second fd that you write to from the other thread to wake up select
.
As suggested in the comments below, closing the fd to wake up select
may not be portable. You can use the second-fd strategy mentioned above to achieve this more portably.
Signal handlers will not interrupt fread
unless they were installed as interrupting, and unhandled signals are never interrupting. The POSIX standard allows handlers installed by the signal
function to be wither interrupting or non-interrupting by default (and on Linux the default to non-interrupting), so if you need a specific behavior, use the sigaction
function and specify the desired sa_flags
. In particular, you need to omit the SA_RESTART
flag. For example:
struct sigaction sa = { .sa_handler = dummy_func, .sa_flags = 0 };
sigaction(SIGUSR1, &sa, 0);
Note that sa_flags
would implicitly be 0 anyway if omitted, but I included it explicitly in the initializer to illustrate. Then you can interrupt the fread
by sending SIGUSR1
with kill
or pthread_kill
.
You can use the kill() syscall.
UPDATE
Turns out I misread your question. As R. pointed out below, kill()
is only for killing processes, not threads.
1. Signals:
Using signals, as many others pointed out, would work. However, as many others also pointed out, the approach has its disadvantages.
2. Select():
Using select() (or other multiplexing function), you can block waiting for data to arrive from more than one file descriptor, and specify a timeout.
Use the timeout to your advantage. Whenever select() returns, check a global variable to see if you must terminate. If you want immediate reaction, keep reading.
3. Select() and pipes:
Multiple fds means you can wait for data arriving through the device you mentioned and, say, a pipe.
Before you create the thread, create a pipe, and then have the thread block on select() monitoring both the device and the pipe. Whenever you want to unblock select whether the device has new data or not, send a byte down the pipe.
If select() tells you it unblocked due to data arriving through the pipe, you can clean up and terminate. Note this method is much more flexible than the signaling method, since you can, besides just using the pipe as a wake-up method, use it to pass useful information or commands.
4. Select(), pipes and signals:
If you are using multiple processes and don't want to/can't pass around a pipe, you can combine both solutions. Create a pipe and install a signal handler for, say, SIGUSR1. In the signal handler, send a byte down the pipe.
Whenever a process sends SIGUSR1, the handler will be called and unblock select(). By examining the fdsets, you will know it was for no other reason than your own program signaling itself.
Take a look at man 2 kill
. (Or see here)
I get the feeling that you don't want to do this, though--most of the time people ignore errno EINTR
and read again. You might want to look into non-blocking reads instead.