首页 文章

使用std :: cin语句进行自动超时

提问于
浏览
2

我写了这个程序

#include<iostream>
using namespace std;
int n;
int main(int argc, char *argv[])
{
  std::cout << "Before reading from cin" << std::endl;

   // Below reading from cin should be executed within stipulated time
   bool b=std::cin >> n;
   if (b)
      std::cout << "input is integer for n and it's correct" << std::endl;
   else
      std::cout << "Either n is not integer or no input for n" << std::endl;
  return 0;
}

这里std :: cin语句将等待控制台输入并进入休眠模式,直到我们提供一些输入并按Enter键 .

我希望std :: cin语句在10秒后超时(如果用户在10秒之间没有输入任何数据,那么编译器将开始执行std :: cin语句下面的程序的下一个语句 .

我能够使用多线程机制解决它 . 以下是我的代码:

#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>

#include<iostream>
using namespace std;
void *thread_function(void *arg);
int input_value;

int main(int argc, char *argv[])
{
    int res;
    pthread_t a_thread;
    void *thread_result;
    res=pthread_create(&a_thread,NULL,thread_function,NULL);
    if(res!=0){
            perror("Thread creation error");
            exit(EXIT_FAILURE);
    }
    //sleep(10);
    cout<<"cancelling thread"<<endl;
    res=pthread_cancel(a_thread);

    cout<<"input value="<<input_value<<endl;
    exit(EXIT_SUCCESS);
 }
 void *thread_function(void *arg)
 {
    int res;
    res=pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
    if(res!=0){
            perror("Unable to set pthread to cancel enbable state");
            exit(EXIT_FAILURE);
    }
    cin>>input_value;
    pthread_exit(&input_value);
 }

但在这里我遇到了一个问题 . 由于睡眠功能要么用户输入值,要么睡眠功能默认睡眠10秒 . 这是我落后的地方 .

如何使用(信号,二进制信号量等)来解决这个问题 . 请将您的答案与我的解决方案(即多线程)联系起来 .

任何信息都是最受欢迎的......

2 回答

  • 1

    我已经尝试了一些解决方案来实现这一点,而我当前的解决方案非常糟糕,但是,它适用于我使用select和poll的其他解决方案失败的地方 .

    我的代码有时会给我一个积极的结果,数据可用,但然后永远阻止 std::cin.get();std::getline(std::cin, STRINGVARIABLE);

    我的解决方案

    // Reset flag, initially true so that if cin blocks it will be reset
    bool Reset = true;
    // Create a c++11 thread to reset cin after a timeout of 100ms
    std::thread ResetThread([&Reset](void){
        // This thread will wait 100ms
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        // Then if the reset flag is still true it will reset cin by closing and opening it
        if (Reset) {
            close(STDIN_FILENO);
            // TODO: Really the output of this open call should be checked for errors
            open("/dev/null", O_RDONLY);
        }
    });
    
    // Now for the standard reading of cin:
    std::string Line;
    std::getline(std::cin, Line);.
    // If cin was read correctly the getline command will return immediately
    // This means that the reset flag will be set to false long before the thread tests it.
    Reset = false;
    // Finally join with the thread.
    ResetThread.join();
    

    此代码可以与select或poll方法(它在我的代码中)连接,以防止每100ms创建一个新线程 .

    显然,这段代码的适当性将取决于你的项目的其余部分,但它对我有用,所以我想我会分享 .

    -- EDIT --

    在PC之间移动之后,似乎这段代码并不像我希望的那样强大 . 我现在已经接受了使用单独的阻塞线程进行输入,请在此处查看我的答案:

    在与非阻塞cin战斗很长一段时间后,似乎唯一可行的方法就是在自己的线程中 .

    请参阅我的答案以获得实施:

    https://stackoverflow.com/a/39499548/1427932

  • 5

    因为你在POSIX机器上,你可以使用例如select检查标准输入上是否有任何内容:

    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(STDIN_FILENO, &fds)
    
    timeval timeout;
    timeout.tv_sec = 5;   // A five-second timeout
    timeout.tv_usec = 0;
    
    int rc = select(STDIN_FILENO + 1, &fds, nullptr, nullptr, &timeout);
    if (rc < 0)
        perror("select");
    else if (rc == 0)
    {
        // Timeout
    }
    else
    {
        // There is input to be read on standard input
    }
    

    使用 poll (由Basile Starynkevitch建议)可以这样做:

    struct pollfd poller;
    poller.fd = STDIN_FILENO;
    poller.events = POLLIN;
    poller.revents = 0;
    
    int rc = poll(&poller, 1, 5);  // Poll one descriptor with a five second timeout
    if (rc < 0)
        perror("select");
    else if (rc == 0)
    {
        // Timeout
    }
    else
    {
        // There is input to be read on standard input
    }
    

相关问题