C++ 使用pthreads查看stdin

C++ 使用pthreads查看stdin,c++,pthreads,stdin,C++,Pthreads,Stdin,我正试图通过pthreads查看stdin是否存在任何内容。我(认为我)需要这样做,因为如果std in中没有任何内容,流访问函数将阻止输入 我觉得这样做的方法是启动一个pthread来检查stdin,然后休眠(1),看看线程是否发现了什么 这是我到目前为止所拥有的。如果没有任何东西通过管道传输到程序中,那么它将按照预期休眠,但是如果stdin中有什么东西,线程将永远不会被触发 #include <iostream> #include <pthread.h> #inclu

我正试图通过pthreads查看stdin是否存在任何内容。我(认为我)需要这样做,因为如果std in中没有任何内容,流访问函数将阻止输入

我觉得这样做的方法是启动一个pthread来检查stdin,然后休眠(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;
}    
#包括
#包括
#包括
使用名称空间std;
void*checkStdIn(void*d){
字符c='\0';
c=cin.peek();
如果(c){
cout您的
sleep(2)
毫无价值,因为它不能保证您的线程在程序终止前2微秒内完成。您需要实现
pthread\u join(thread,NULL);
以等待线程完成。请参阅此处以获取一个好的示例


另外,cin.peek()将阻止等待输入。这就是它的设计方式。请参阅此处的示例。

您不需要pthreads,您可以使用
select(2)
poll(2)
来知道是否可以在不阻止应用程序的情况下查看stdin。为此,我编写了
my\u peek()
函数,您只需通过等待输入的秒数即可(如果不想等待,甚至可以通过0):

有关更多信息,请查看位于的
选择(2)
手册页面


PS:您可以尝试依赖cpluplus站点中解释的\u avail()
中的
std::cin.rdbuf()->返回的值,甚至在
readsome()中<代码> > ISTRAM< <代码>类,但它们通常依赖于GNU C++库中未公开的文件>代码>缓冲区。不要这样做,否则你可能会失败。

< P> <强>编辑:< /强> BAWH,费尔南多的忍者:)/P> 好吧,所以我不能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;
}
#包括
#包括
无效切换_规范(布尔开启){
结构termios终端设置;
//获取现有的终端设置
tcgetattr(0/*标准输入*/,&终端设置);
如果(打开){
//禁用规范模式
终端设置.c\u lflag&=~ICANON;
//至少读取一个字符。
终端设置。c_cc[VMIN]=1;
}否则{
//启用规范模式
终端_settings.c_lflag |=ICANON;
}
tcsetattr(0/*stdin*/、TCSANOW和终端设置);
返回;
}
int main(常量int argc,常量char*argv[]){
//读取超时,如果您根本不想阻塞,则可以为0。
结构timeval to={5/*秒*/,0/*毫秒*/};
fd_设置读取_fds;
int-ret=0;
//打开规范模式
切换_规范(真);
FD_零(&read_fds);
FD_集(0,读取&u fds);
//要选择()的第一个参数是最高的文件
//集合中的描述符+1,因此在本例中,因为
//STDIN==0,我们通过1。这实际上是完全正确的
//在包括Windows在内的多个平台上被忽略。
if((ret=select(1,&read_fds/*read set*/,NULL/*write set*/,NULL/*error set*/,&to/*timeout*/)==0){

std::cout程序在可以执行线程之前结束。为什么不sleep()呢不过可以补救吗?您的线程只检查一次输入,没有发现任何内容并终止。@Ty:如果您想等待线程完成,请使用phthread\u join忘记我之前的评论,这是错误的。
睡眠时间实际上是以整秒计的,但无论如何都需要加入。对于支持pthreads的环境,如果您是n一个支持POSIX的平台。当操作系统可以告诉你文件描述符上的状态时,无需生成线程。(+1)除了
std::cin
通常是缓冲的,所以这通常不起作用。(尝试peek+在循环中一次读取一个字符,从文件重定向stdin,你就会明白我的意思。)谢谢,尼莫。我修复了这个示例并添加了避免缓冲区问题的提示。@Fernando哇,谢谢你的回答,效果很好……我感谢你的帮助:)
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 */
}
#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;
}