是否可以为std :: cin设置超时?

时间:2012-01-29 12:30:51

标签: c++ timeout stdin

是否可以为std :: cin设置超时? 例如,std :: cin在10秒内没有收到任何数据 - 它会抛出异常或返回错误。

编辑:

那么来自Boost library的计时器呢?据我所知,它是便携式库。是否有可能要求Boost库的计时器在预定义的时间段后抛出异常?我想它可以解决这个问题。

3 个答案:

答案 0 :(得分:8)

无法以便携方式设置std::cin的超时时间。即使采用非便携式技术,这样做也并非完全无关紧要:您需要替换std::cin的流缓冲区。

在UNIX系统上,我会将std::cin使用的默认流缓冲区替换为使用文件描述符0来读取输入的自定义缓冲区。要实际读取输入,我将使用poll()来检测输入的存在并在此函数上设置超时。根据{{​​1}}的结果,我会读取可用输入或失败。为了可能处理未转发到文件描述符的类型字符,但是在输入换行符之前也可以关闭缓冲完成。

使用多个线程时,您可以创建一个便携式过滤流缓冲区,它使用线程来读取实际数据,另一个线程使用定时条件变量,等待第一个线程发出信号表明它接收到数据或超时直到到期为止。请注意,您需要防止虚假唤醒以确保在没有输入时确实达到了超时。这样可以避免必须修改从poll()读取数据的实际方式,尽管它仍然会替换std::cin使用的流缓冲区,以使该功能可通过此名称访问。

答案 1 :(得分:2)

我只是弄清楚如何做到这一点,轮询std :: cin文件描述符。

如果发生超时并且没有发生任何事件,

poll函数返回0,如果发生了某事,则返回1,如果发生错误,则返回-1。

#include <iostream>

#include <signal.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>


bool stop = false;

void intHandler(int dummy)
{
    stop = true;
}

std::string readStdIn()
{
    struct pollfd pfd = { STDIN_FILENO, POLLIN, 0 };

    std::string line;
    int ret = 0;
    while(ret == 0)
    {
        ret = poll(&pfd, 1, 1000);  // timeout of 1000ms
        if(ret == 1) // there is something to read
        {
            std::getline(std::cin, line);
        }
        else if(ret == -1)
        {
            std::cout << "Error: " << strerror(errno) << std::endl;
        }
    }
    return line;
}

int main(int argc, char * argv[])
{
    signal(SIGINT, intHandler);
    signal(SIGKILL, intHandler);

    while(!stop)
    {
        std::string line = readStdIn();
        std::cout << "Read: " << line << std::endl;
    }
    std::cout << "gracefully shutdown" << std::endl;
}

答案 2 :(得分:0)

这段代码使用线程来完成。

#include <iostream>
#include <thread>
#include <chrono>
#include <string>

int main()
{
    int number;
    bool wasInput= false;

    std::cout << "Enter a number in 10 seconds:\n";
    std::thread t1([&]() {
        std::cin >> number;
        wasInput = true;
        });
    
    std::this_thread::sleep_for(std::chrono::seconds(10));
    t1.detach();

    if (wasInput)
        std::cout << "\nENTERED IN TIME\nnumber = " << number << '\n';
    else
        std::cout << "\nTIME IS OUT\n";

    return 0;
}

但是如果你运行它,你会看到即使用户输入它也会等待 10 秒 某物。所以你可以像这样改进它:

#include <iostream>
#include <thread>
#include <chrono>
#include <string>

int main()
{
    int number;
    bool wasInput = false;

    std::cout << "Enter a number in 10 seconds:\n";

    time_t start = time(NULL);
    time_t waitTime = 10;
    while (time(NULL) < start + waitTime && !wasInput)
    {
        std::thread t1([&]() {
            std::cin >> number;
            wasInput = true;
            });
        std::this_thread::sleep_for(std::chrono::milliseconds(20));
        t1.detach();
    }
    
    if (wasInput)
        std::cout << "\nENTERED IN TIME\nnumber = " << number << '\n';
    else
        std::cout << "\nTIME IS OUT\n";

    return 0;
}