简体   繁体   English

如何在不阻塞输入的情况下使用 getline?

[英]How can I use getline without blocking for input?

Is there any method to call getline() and, if there is no input given, not to block and waiting?是否有任何方法可以调用getline()并且如果没有给出输入,则不阻塞和等待?

I have the following code:我有以下代码:

 while(true){
    if(recv(sd, tBuffer, sizeof(tBuffer), MSG_PEEK | MSG_DONTWAIT) > 0) break;
    getline(cin,send);
 }

I want to wait for an input, but if I receive some data at sd socket, I want stop waiting for the data and exit the while .我想等待输入,但如果我在sd套接字接收到一些数据,我想停止等待数据并退出while My code right now, just stucks on first iteration at getline() .我现在的代码只是停留在getline()第一次迭代中。 I want to evaluate getline() , and if is no input available, go back at if .我想评估getline() ,如果没有可用的输入,请返回if

Is this possible?这可能吗?

PS: I tried with cin.peek() , but that blocks for input too. PS:我尝试过cin.peek() ,但它也阻止了输入。

You should be able to do this by setting non-blocking mode on standard input, file descriptor 0:您应该能够通过在标准输入、文件描述符 0 上设置非阻塞模式来做到这一点:

int flags = fcntl(0, F_GETFL, 0);
fcntl(0, F_SETFL, flags | O_NONBLOCK);

Now, if there's no input available, the underlying read() system call will return 0, and std::cin will think that this is end of file, and set eof() on std::cin .现在,如果没有可用的输入,底层的read()系统调用将返回 0,并且std::cin会认为这是文件结尾,并在std::cin上设置eof()

When you wish to read from standard input again, just clear() the stream's state.当您希望再次从标准输入读取时,只需clear()流的状态。

The only complicating factor here is that this makes it difficult to detect a real end-of-file condition on std::cin .这里唯一的复杂因素是这使得很难在std::cin上检测到真正的文件结束条件。 Not much a problem when standard input is an interactive terminal;当标准输入是交互式终端时,问题不大; but if standard input can be a file this is going to be an issue.但如果标准输入可以是一个文件,这将是一个问题。

In that case, your only realistic option is to forego std::cin completely, put non-blocking mode on file descriptor 0, poll() or select() it, to determine when there's something to read, then read() it.在这种情况下,您唯一现实的选择是完全放弃std::cin ,将非阻塞模式置于文件描述符 0、 poll()select()上,以确定何时有内容要读取,然后read()它。

Although you could also use poll() or select() with std::cin , this is going to get complicated, because you will need to explicitly check if there's anything already buffered in std::cin 's streambuf , because that would, obviously, preempt any kind of poll() or select() checking;尽管您也可以将poll()select()std::cin ,但这会变得复杂,因为您需要明确检查std::cinstreambuf是否已经缓冲了任何内容,因为那样会,显然,抢占任何类型的poll()select()检查; but by attempting to read something from std::cin , you still run the risk of reading the buffered data, then attempting to read() from the underlying file descriptor that's now in non-blocking mode, this resulting in a fake end-of-file condition.但是通过尝试从std::cin读取某些内容,您仍然冒着读取缓冲数据的风险,然后尝试从现在处于非阻塞模式的底层文件描述符中read() ,这会导致假结束-文件条件。

To summarize: you need invest some additional time reading and understanding how file streams, and stream buffers work;总结一下:您需要花一些额外的时间来阅读和理解文件流和流缓冲区的工作原理; and how file descriptors actually work, and how non-blocking mode works;以及文件描述符的实际工作方式,以及非阻塞模式的工作方式; in order to figure out the correct logic you will need to use.为了找出您需要使用的正确逻辑。

Oh, and if you insist on going the non-blocking route with std::cin , and getline() , you will have no easy way to determine if the string returned by getline() ends because getline() actually read a newline from standard input, or it reached a premature fake-end of file condition and not the entire line of input has actually been read.哦,如果你坚持使用std::cingetline()去非阻塞路由,你将没有简单的方法来确定getline()返回的字符串是否结束,因为getline()实际上从标准输入,或者它过早地达到了文件条件的假结束,而不是实际读取了整行输入。

So, with non-blocking mode, and std::cin , you'll be pretty much forced to use read() , instead of getline() .因此,对于非阻塞模式和std::cin ,您将不得不使用read()而不是getline()

The istream::getsome() method can be used to perform non-blocking reads.istream::getsome()方法可用于执行非阻塞读取。 You can use it to build a non-blocking equivalent of std::getline .您可以使用它来构建std::getline的非阻塞等效项。

bool getline_async(std::istream& is, std::string& str, char delim = '\n') {

    static std::string lineSoFar;
    char inChar;
    int charsRead = 0;
    bool lineRead = false;
    str = "";

    do {
        charsRead = is.readsome(&inChar, 1);
        if (charsRead == 1) {
            // if the delimiter is read then return the string so far
            if (inChar == delim) {
                str = lineSoFar;
                lineSoFar = "";
                lineRead = true;
            } else {  // otherwise add it to the string so far
                lineSoFar.append(1, inChar);
            }
        }
    } while (charsRead != 0 && !lineRead);

    return lineRead;
}

This functions works identically to the original std::getline() function except it always returns instantly.此函数与原始std::getline()函数的工作方式相同,只是它总是立即返回。 I've got it on my gists because it comes in handy occasionally.我已经把它放在了我的要点上,因为它偶尔会派上用场。

I used select() to retrieve the status of the stdin file descriptor.我使用 select() 来检索 stdin 文件描述符的状态。 This worked on Ubuntu and on an embedded Linux board.这适用于 Ubuntu 和嵌入式 Linux 板。 If stdin still has not received an enter keystroke from the user, select will wait some time and report that stdin is not ready.如果 stdin 仍未收到用户的输入键,select 将等待一段时间并报告 stdin 未准备好。 stopReading can stop monitoring the stdin and continue on other stuff. stopReading 可以停止监视标准输入并继续处理其他内容。 You can edit it as needed.您可以根据需要对其进行编辑。 It may not work on special input tty's.它可能不适用于特殊输入 tty。

#include <sys/select.h>

static constexpr int STD_INPUT = 0;
static constexpr __suseconds_t WAIT_BETWEEN_SELECT_US = 250000L;

// Private variable in my class, but define as needed in your project
std::atomic<bool> stopReading;

...

std::string userInput = "";
while (false == stopReading)
{
    struct timeval tv = { 0L, WAIT_BETWEEN_SELECT_US };
    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(STD_INPUT, &fds);
    int ready = select(STD_INPUT + 1, &fds, NULL, NULL, &tv);

    if (ready > 0)
    {
        std::getline(std::cin, userInput);
        break;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在cpp中如何使用getline()在没有交互式输入的情况下获取完整句子? - In cpp how to use getline() get full sentence without interactive input? 如何使用getline将值输入C ++中的类? - How can you use getline to input values to classes in C++? 如何正确使用“ getline(cin,input);” - How do I correctly use “getline(cin, input);” 如何在不循环的情况下使用 getline 读取文件? - How can I read files using getline without it looping? 为什么我可以在不使用std :: getline的情况下调用getline? - Why can I call getline without using std::getline? 为什么我不能在没有字符串流的情况下运行我的 getline 代码? 如何使用 stringstream 使此代码工作? - Why can't I run my getline code without the stringstream? How do i use stringstream to make this code work? 如何在 getline() 中使用多个分隔符 (',', '/n')? - How can I use multiple delimiters (',' , '/n') with getline()? 如何在不使用 getline 的情况下在 C++ 中获取输入字符串直到行尾 - How to Take Input String till End Of Line in C++ without the Use of getline 非阻塞std :: getline,如果没有输入则退出 - non-blocking std::getline, exit if no input 如何使用 getline 和 stringstream 解析格式化的日期和时间输入? - How do I use getline and stringstream to parse formatted date and time input?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM