【发布时间】:2017-03-14 13:39:26
【问题描述】:
我正在编写一个程序,它同时从 4 个摄像头捕获视频,所以我有 4 个线程来控制每个摄像头。在每个线程中,我希望它继续捕获,直到我按下一个键并且该键对应于 'q' 或其他东西。
对于按键句柄,我搜索了互联网并找到了这样的方法:
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
int kbhit(int key) {
int ch;
int old_file_status;
struct termios old_term_attr;
struct termios new_term_attr;
tcgetattr(STDIN_FILENO, &old_term_attr);
new_term_attr = old_term_attr;
new_term_attr.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &new_term_attr);
old_file_status = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, old_file_status | O_NONBLOCK);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &old_term_attr);
fcntl(STDIN_FILENO, F_SETFL, old_file_status);
if(ch == c)
return 1;
return 0;
}
在我的 VideoCapture 类中,我有这样的代码(不完整):
static void *capureVideo(void *para) {
// Some code...
while(!(kbhit('q') {
// Read frame...
}
}
void creatThread() {
if (pthread_create(&threadID, NULL, capureVideo, this) != 0) {
perror("thread create faild");
exit(EXIT_FAILURE);
}
}
当程序运行时,一旦我按 'q' 键 4 次,程序就会退出,控制权会交还给 shell。但是在某些特定情况下(我不完全知道,它不会每次都发生)它会导致一个问题,那就是当我在 shell 中输入命令时,我输入的字符不会出现。当我按下回车时,命令被提交。
我搜索了这个问题,发现是:https://askubuntu.com/a/172747,表示我的终端属性没有正确重置。但是在按键句柄代码中我注意到这两行代码
tcsetattr(STDIN_FILENO, TCSANOW, &old_term_attr);
fcntl(STDIN_FILENO, F_SETFL, old_file_status);
确实重置了终端属性。所以我想知道它是否与多线程有关。我是多线程编程的新手,自己无法解决,所以有人可以帮助我吗?任何建议都非常感谢。
【问题讨论】:
-
如果程序被 CTRL-C 或其他信号终止,手动重置终端属性将完全没有任何效果。除了将终端属性显式重置为其默认值外,还应通过
sigaction()为至少SIGINT、SIGHUP、SIGTERM和可能的SIGQUIT设置信号处理程序,这将重置终端属性为其默认值。 -
这里还有一个竞争条件,一个线程在另一个线程进入
getchar()之前将终端属性重置为默认值,并最终阻塞标准输入。总的来说,这是一种错误的方法。终端应在开始时仅设置一次非阻塞模式和非规范处理模式,并且仅在程序终止之前重置。而不是getchar()在文件描述符 0 上使用read()。 -
The terminal should be set to non blocking mode and non-canonical processing mode only once, at the beginning, and reset only before the program terminates.这是否意味着我可以使用单例模式?另外,你能解释一下为什么不推荐getchar()。非常感谢。 @SamVarshavchik
标签: c++ linux multithreading keypress