The most portable solution I can think of is:
- Use
pipe()
to construct two FDs, one a reader and the other a writer. Give the reader to your read()
loop; give the writer to whoever needs to terminate the reader.
- Use
select()
from the read thread to wait for readability of both stdin and the reader pipe.
- If stdin becomes readable, read a character, process it, and then restart the loop.
- If the reader pipe becomes readable, close it and terminate the loop.
Now, all you should have to do is close the other end of the pipe and this will wake up the reader thread out of its select()
and it should then terminate.
The traditional approach involves using signals, however this pipe-based solution allows you to check for input on stdin as well as check if you should terminate using the same polling mechanism.
Note that mixing getchar()
and select()
will not work, since getchar()
will effectively use fread()
under the hood, and the buffering performed by fread()
can cause select()
to block even though there is data available. Use read()
instead. Here is an example program I used to test this approach.
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/select.h>
void * entry_point(void * p) {
int readpipe = *(int *)p;
fd_set rfds;
char c;
for (;;) {
FD_ZERO(&rfds);
FD_SET(STDIN_FILENO, &rfds);
FD_SET(readpipe, &rfds);
while (select(readpipe + 1, &rfds, NULL, NULL, NULL) == 0);
if (FD_ISSET(readpipe, &rfds)) {
close(readpipe);
break;
}
if (FD_ISSET(STDIN_FILENO, &rfds)) {
if (read(STDIN_FILENO, &c, sizeof(c)) > 0) {
printf("Read: %d\n", c);
}
}
}
printf("Thread terminating\n");
pthread_exit(NULL);
}
int main() {
pthread_t thread;
int r;
int pipes[2];
pipe(pipes);
if (r = pthread_create(&thread, NULL, entry_point, &pipes[0])) {
printf("Error: %d\n", r);
return 1;
}
sleep(5);
printf("Closing pipe and joining thread.\n");
close(pipes[1]);
pthread_join(thread, NULL);
pthread_exit(NULL);
}
Example run:
$ time ./test
1
Read: 49
Read: 10
2
Read: 50
Read: 10
3
Read: 51
Read: 10
4
Read: 52
Read: 10
5
Read: 53
Read: 10
Closing pipe and joining thread.
Thread terminating
real 0m5.004s
user 0m0.004s
sys 0m0.000s