I'am writing a program which capturing videos from 4 cameras simultaneously, so I have 4 threads to control each camera. In each thread I want it to continue capturing until I hit a key and that key corresponds to 'q' or something.
For keypress handle I search the Internet and found method like this:
#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;
}
And in my VideoCapture class I have code like this (not complete):
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);
}
}
When the program runs, once I hit the key 'q' 4 times the program did quits and control is given back to the shell. But in some certain circumstances (I don't exactly know, it doesn't happen every time) it lead to a problem, that is when I then go and type commands into the shell, the characters I type don't show up. When I press enter the commands are submitted.
I search this problem and found this: https://askubuntu.com/a/172747, which indicates that my terminal attributes were not reset properly. But in the keypress handle code I noticed that this two lines of code
tcsetattr(STDIN_FILENO, TCSANOW, &old_term_attr);
fcntl(STDIN_FILENO, F_SETFL, old_file_status);
did reset the terminal attributes. So I wonder if it's relevant to the multithread. I'm new to mutlithread programming and couldn't solve it myself, so could someone help me? Any suggestions are highly appreciated.
You have multiple threads trying to change parameters of the (static) terminal at the same time:
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);
Without this being locked, your terminal attributes are completely random. The fixes are to either protect this with a mutex, or if you spawn another thread to read the keyboard and set a flag for when 'q' has been pressed; which your other threads can read, you can do something like
(pardon the psudo code)
bool shouldRun = true
void captureThreadMain {
while (shouldRun) {
captureFrame();
}
}
void keyboardPressMain {
while (getKey('q'));
shouldRun = false;
}
This will mean that you only need to press 'q' once to stop all your frame collecting threads.