我有一个进行大量处理的小程序。您可以通过按回车键来打印进度。
我实现这一点的方法是在主线程中完成处理,同时我有一个 pthread 在 getchar() 上不断循环以等待输入键。
问题是当我完成处理时。发生这种情况时,主线程完成,但仍等待按 enter,因为 getchar() 被阻塞。
如何“取消”getchar()?
我能想到的最便携的解决方案是:
pipe()
构造两个 FD,一个是 reader,另一个是 writer。给读者你的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
假设您想走这条路,您可以使用 pthread_kill 强制您的 getchar 线程退出。请参阅Pthread 库中的终止线程。同样,虽然不是最佳编程实践。
有一个共享变量怎么样。然后在每次 getchar() 返回后,它都会获取一个锁,然后检查是否设置了这个共享变量。如果不是,那么它会执行您所做的任何事情,如果已设置,则线程退出。这样,当 main 退出时,它会获取一个锁,设置变量,释放锁,打印到标准输入,然后等待另一个线程退出。有点复杂,但它应该工作。〜本
使用 printf() 将字符写入标准输入。
我真的很喜欢关闭标准输入的想法。这很好,可能会奏效。
以下关闭标准输入: close(0); fclose(标准输入);关闭(STDIN_FILENO);守护进程(0, 0);
您也可以从主线程向标准输入写入特殊的字符序列或 EOF,然后将其关闭。