3

我写了程序

#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 秒。这是我落后的地方。

我该如何解决这个问题,比如使用(信号、二进制信号量等)。请把你的答案与我的解决方案联系起来(即多线程)。

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

4

2 回答 2

5

由于您在 POSIX 机器上,您可以使用 egselect检查标准输入上是否有任何内容:

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
}
于 2013-09-03T09:54:16.320 回答
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 方法(在我的代码中)结合使用,以防止每 100 毫秒创建一个新线程。

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

- 编辑 -

在 PC 之间移动之后,这段代码似乎没有我希望的那么健壮。我现在已经接受了仅使用单独的阻塞线程进行输入,请在此处查看我的答案:

在与非阻塞 cin 斗争了很长时间之后,似乎唯一可靠的方法是在它自己的线程中。

请在此处查看我的答案以获取实现:

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

于 2014-07-04T14:04:15.887 回答