我能想到的最便携的解决方案是:
- 使用
pipe() 构造两个FD,一个是读取器,另一个是写入器。将读者交给您的read() 循环;将作者交给需要终止读者的人。
- 使用读取线程中的
select() 等待标准输入和读取器管道的可读性。
- 如果标准输入变得可读,则读取一个字符,对其进行处理,然后重新启动循环。
- 如果读取器管道变得可读,请将其关闭并终止循环。
现在,您需要做的就是关闭管道的另一端,这会将阅读器线程从其select() 中唤醒,然后它应该终止。
传统方法涉及使用信号,但这种基于管道的解决方案允许您检查标准输入上的输入以及检查是否应使用相同的轮询机制终止。
请注意,混合getchar() 和select() 将不起作用,因为getchar() 将在后台有效地使用fread(),并且fread() 执行的缓冲可能会导致select() 阻塞,即使有可用的数据。请改用read()。这是我用来测试这种方法的示例程序。
#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);
}
示例运行:
$ 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