我正在试图查看stdin以查看是否有任何使用pthreads的东西。我(我想)我需要这样做,因为如果std中没有任何内容,流访问函数将阻止输入。
我觉得这样做的方法是启动一个检查stdin的pthread,然后睡眠(1)并查看线程是否找到了什么。
这是我到目前为止所拥有的。如果没有任何东西通过管道进入程序,那么它将按预期睡眠,但如果某些东西在stdin中,则线程永远不会被触发。
#include <iostream>
#include <pthread.h>
#include <stdlib.h>
using namespace std;
void *checkStdIn(void *d){
char c = '\0';
c = cin.peek();
if (c){
cout << c << endl;
}
}
int main(int argc, char *argv[]){
pthread_t thread;
int rc;
rc = pthread_create(&thread, NULL, checkStdIn, NULL);
if (rc){
cerr << "Error no. " << rc << endl;
exit(EXIT_FAILURE);
}
sleep(2);
return 0;
}
答案 0 :(得分:4)
您不需要pthreads,如果您可以在不阻止应用程序的情况下查看stdin,则可以使用select(2)
或poll(2)
来知道。为此,我编写了my_peek()
函数,你需要传递你想要等待输入的秒数(如果你不想等待,你甚至可以传递0):
/* According to POSIX.1-2001 */
#include <sys/select.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
int
my_peek(unsigned int nsecs)
{
struct timeval timeout;
fd_set rfds;
int fd;
// stdin file descriptor is 0
fd = 0;
timeout.tv_sec = nsecs;
timeout.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
if (select(fd + 1, &rfds, NULL, NULL, &timeout) > 0)
return std::cin.peek();
return -1;
}
int
main(void)
{
int peek;
peek = my_peek(2);
if (peek != -1) {
std::cout << "we could peek without freezing" << std::endl;
std::cout << "my_peek() returned " << peek << std::endl;
} else {
std::cout << "we could not peek without freezing" << std::endl;
}
return 0;
}
请注意,依靠select(2)
判断cin
对象或stdin
FILE
结构中是否有数据是不明智的,因为正如Nemo所说,他们是BUFFERED。最好的办法是使用read(2)
避免在此示例中使用“cin”。 my_peek()
的改进版本如下所示:
int
my_peek(unsigned int nsecs)
{
struct timeval timeout;
fd_set rfds;
int fd;
unsigned char c;
// stdin file descriptor is 0
fd = 0;
timeout.tv_sec = nsecs;
timeout.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
if (select(fd + 1, &rfds, NULL, NULL, &timeout) <= 0)
return -1;
if (read(fd, &c, 1) != 1)
return -1;
return static_cast<int>(c); /* or "return (int)c" for C-only programs */
}
有关详细信息,请查看http://linux.die.net/man/2/select上的select(2)
手册页。
PS:您可以尝试依赖cpluplus网站http://www.cplusplus.com/reference/iostream/streambuf/in_avail/中解释的std::cin.rdbuf()->in_avail()
返回的值,甚至readsome()
的{{1}}方法class,但它们通常依赖于istream
缓冲区,而该缓冲区未在GNU C ++库中公开。不要这样做,否则你可能会失败。
答案 1 :(得分:0)
您的sleep(2)
毫无价值,因为它不能保证您的线程在程序终止前2微秒内完成。您需要实现pthread_join(thread, NULL);
以等待线程完成。请参阅此处以获取良好的pthread示例。
此外,cin.peek()将阻止等待输入。这就是它的设计方式。请参阅此处以获取cin.peek的示例。
答案 2 :(得分:0)
编辑: Bawh,费尔南多的忍者:)
好的,所以我不能100%确定最佳答案是什么,因为我不知道你希望你的程序最终做什么。
首先,这不是应该使用线程解决的问题。线程并不是万能的解决方案,与其他解决方案相比,通常会产生巨大的开销。因为您已经在使用pthreads
,所以我认为Windows兼容性不是问题。
第一步是禁用规范模式,这样您就可以在不必等待enter
的情况下获取字符。如果您100%确定stdin
永远不会成为终端,则可以跳过此步骤。
#include <iostream>
#include <termios.h>
void toggle_canonical(bool on) {
struct termios terminal_settings;
// Get the existing terminal settings
tcgetattr(0 /* stdin */, &terminal_settings);
if(on) {
// Disable canonical mode
terminal_settings.c_lflag &= ~ICANON;
// Read at least one character.
terminal_settings.c_cc[VMIN] = 1;
} else {
// Enable canonical mode
terminal_settings.c_lflag |= ICANON;
}
tcsetattr(0 /* stdin */, TCSANOW, &terminal_settings);
return;
}
int main(const int argc, const char* argv[]) {
// The read timeout, which can be 0 if you don't want to block at all.
struct timeval to = {5 /* seconds */, 0 /* miliseconds */};
fd_set read_fds;
int ret = 0;
// Turn canonical mode on
toggle_canonical(true);
FD_ZERO(&read_fds);
FD_SET(0, &read_fds);
// The first parameter to select() is the highest file
// descriptor in the set + 1, so in this case because
// STDIN == 0, we pass 1. This is actually completely
// ignored on several platforms, including Windows.
if((ret = select(1, &read_fds /* read set */, NULL /* write set */, NULL /* error set */, &to /* timeout */)) == 0) {
std::cout << "You didn't type anything in time." << std::endl;
} else if (ret == 1) {
std::cout << "Yay, you typed something in time!" << std::endl;
} else if (ret == -1) {
std::cout << "Oh no, an error occured!" << std::endl;
}
// Turn canonical mode off
toggle_canonical(false);
return 0;
}