非阻塞std :: getline,如果没有输入,则退出 [英] non-blocking std::getline, exit if no input

查看:50
本文介绍了非阻塞std :: getline,如果没有输入,则退出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前,我有一个程序可以从标准输入中读取内容,偶尔如果没有输入,该程序只需保持运行即可,通常这是一个测试脚本,可以说没有输入".

程序-v1 -v2 -v3<输入>输出

v1-v3分别是命令行参数

基本上,如果没有给出输入",程序将退出命令行参数及其各自的含义,然后退出.

但是,如果现在给它一个空的测试文件,或者只是在std :: getline上运行它后在不按Enter的情况下运行它,我就用来输入命令.

  while(std :: getline(std :: cin,foo){做东西} 

其中foo是一个字符串.

如何让它至少运行一次并至少执行一次代码,然后在无输入的情况下退出?在输入的情况下,标准输入中的每一行都会出现一次 do .

是否可以切换到do-while循环,并检查pre循环是否有任何输入?

类似

 如果cin为空设置标志做{做东西检查标志}while(getline) 

还是非阻塞io在c ++中是不可能的?

这个问题似乎一遍又一遍地重复了,但是我找不到一个明确的答案,甚至找不到与平台无关的答案(该程序本质上是学术性的,在Windows上进行编码,并在Unix上进行了测试.)

解决方案

异步使用std :: cin可能是完成此工作的唯一方法,因为iostream并非设计为具有非阻塞行为.这是一个示例:

该代码已注释,因此应易于理解.这是一个线程安全的类,可让您使用std :: cin异步获取行.

非常容易用于异步CLI getline,我的计算机上的CPU使用率为0%.它在Windows 10上的Visual Studio 2015 c ++ Win32控制台调试和发布模式下运行良好.如果它在您的操作系统或环境中不起作用,那就太糟糕了.

  #include< iostream>#include< string>#include< thread>#include< mutex>#include< atomic>使用命名空间std;//此代码在Windows 10上的Visual Studio 2015 c ++ Win32控制台调试和发布模式下运行良好.//如果它不能在您的操作系统或环境中运行,那就太糟糕了;猜想您必须修复它.:(//您可以随意使用此代码,但请随意,但有一个例外:请勿抄袭!//(您可以将其包含在更大的项目中,而无需付出任何功劳.)AsyncGetline类{上市://AsyncGetline是一个允许异步CLI getline风格输入的类//(使用0%的CPU使用率!),普通的iostream使用率是不容易允许的.AsyncGetline(){输入=";sendOverNextLine = true;continueGettingInput = true;//启动一个新的分离线程,一遍又一遍地调用getline并检索要处理的新输入.线程([&](){//getline调用的输入的非同步字符串.字符串syncInput;char nextCharacter;//获取异步输入行.做{//以空行开头.syncInput =";//一次异步处理一个输入字符,直到到达一个新的行字符为止.而(continueGettingInput){//查看是否有任何输入字符(异步).而(cin.peek()== EOF){//确保在必要时总是让另一个线程屈服.不要在这里睡觉//仅屈服,以确保处理将尽可能地响应.this_thread :: yield();}//获取已知可用的下一个字符.nextCharacter = cin.get();//检查换行符.如果(nextCharacter =='\ n'){休息;}//由于此字符不是换行符,因此请将其添加到syncInput字符串中.syncInput + = nextCharacter;}//准备随时停止检索输入.如果(!continueGettingInput){休息;}//等待,直到处理线程准备处理下一行.同时(continueGettingInput&!sendOverNextLine){//确保在必要时总是让另一个线程屈服.不要在这里睡觉//仅屈服,以确保处理将尽可能地响应.this_thread :: yield();}//准备随时停止检索输入.如果(!continueGettingInput){休息;}//安全地发送下一行输入以在处理线程中使用.inputLock.lock();输入=同步输入;inputLock.unlock();//发出信号,尽管该线程将在下一行中读取,//直到处理线程准备就绪,它才将其发送出去.sendOverNextLine = false;}while(continueGettingInput&&input!="exit");}).分离();}//停止获取异步CLI输入.〜AsyncGetline(){//停止getline线程.continueGettingInput = false;}//获取下一行输入(如果有);如果不是,请睡眠一毫秒并返回一个空字符串.字符串GetLine(){//查看下一行输入(如果有)是否已准备好进行处理.如果(sendOverNextLine){//等待输入时不要消耗CPU;this_thread :: yield()//仍然会消耗大量的CPU,因此必须使用睡眠.this_thread :: sleep_for(chrono :: milliseconds(1));返回 "";}别的{//从getline线程检索下一行输入,并将其存储以供返回.inputLock.lock();字符串returnInput =输入;inputLock.unlock();//此外,向getline线程发送信号,告知它可以继续//发送到下一行输入(如果有).sendOverNextLine = true;return returnInput;}}私人的://跨线程安全的布尔值,告诉AgetGetline分解时,getline线程停止.原子< bool>ContinueGettingInput;//Cross-thread-safe布尔值,表示处理线程何时准备好用于下一个输入行.//这是为了防止以前的任何行被新的输入行覆盖而没有//通过在处理线程就绪时仅处理进一步的getline输入来使用队列.原子< bool>sendOverNextLine;//Mutex锁,以确保一次只有一个线程(处理vs. getline)正在访问输入字符串.互斥输入锁;//由于inputLock互斥锁,每个线程可以安全地使用//string.字符串输入};无效main(){AsyncGetline股份公司;字符串输入一会儿(true){//异步获取下一行输入(如果有).自动功能//如果没有getline输入,则睡眠一毫秒.输入= ag.GetLine();//检查是否有任何输入.如果(!input.empty()){//打印出用户的输入以演示正在处理的输入.cout<<"{"<<输入<<} \ n";//检查退出条件.如果(输入==退出"){休息;}}//每隔一段时间打印出一个空格字符以显示异步性.//cout<<";//this_thread :: sleep_for(chrono :: milliseconds(100));}cout<<"\ n \ n";系统(暂停");} 

Currently I have a program that reads from the standard input, occasionally the program needs to just keep running if no input is made, usually this is a test script there is no 'enter' so to speak.

program -v1 -v2 -v3 <input >output

v1 - v3 are command line arguments respectively

Basically the program spits out the command line arguments and their respective meaning to the program if no 'input' is given and then should exit.

However at the moment if give it an empty test file or just run without pressing enter after running it blocks on the std::getline I use to input the commands.

while(std::getline(std::cin,foo)
{do stuff}

where foo is a string.

How do I get it to just run through and do stuff at least once then exit in the event of no input? In the event of input the do stuff occurs once for every line in standard input.

Would a switch to a do-while loop, with a check pre loop as to whether it's got any input, work?

Something like

if cin empty
set flag

do
 {do stuff
 check flag}
while(getline)

or is non-blocking io not possible in c++?

This question seems to be rehashed over and over but I couldn't find a definitive answer or even an answer that was platform agnostic(this program is academic in nature, coded on windows and tested on unix).

解决方案

Using std::cin asynchronously might be the only way to make this work, as iostream is not designed to have non-blocking behavior. Here is an example:

The code is commented so it should be easy to understand. It's a thread-safe class that lets you asynchronously get a line using std::cin.

Very easy to use for asynchronous CLI getline purposes, with 0% CPU usage on my computer. It works perfectly well on Windows 10 in Visual Studio 2015 c++ Win32 Console Debug and Release mode. If it doesn't work in your OS or environment, that's too bad.

#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <atomic>

using namespace std;

//This code works perfectly well on Windows 10 in Visual Studio 2015 c++ Win32 Console Debug and Release mode.
//If it doesn't work in your OS or environment, that's too bad; guess you'll have to fix it. :(
//You are free to use this code however you please, with one exception: no plagiarism!
//(You can include this in a much bigger project without giving any credit.)
class AsyncGetline
{
    public:
        //AsyncGetline is a class that allows for asynchronous CLI getline-style input
        //(with 0% CPU usage!), which normal iostream usage does not easily allow.
        AsyncGetline()
        {
            input = "";
            sendOverNextLine = true;
            continueGettingInput = true;

            //Start a new detached thread to call getline over and over again and retrieve new input to be processed.
            thread([&]()
            {
                //Non-synchronized string of input for the getline calls.
                string synchronousInput;
                char nextCharacter;

                //Get the asynchronous input lines.
                do
                {
                    //Start with an empty line.
                    synchronousInput = "";

                    //Process input characters one at a time asynchronously, until a new line character is reached.
                    while (continueGettingInput)
                    {
                        //See if there are any input characters available (asynchronously).
                        while (cin.peek() == EOF)
                        {
                            //Ensure that the other thread is always yielded to when necessary. Don't sleep here;
                            //only yield, in order to ensure that processing will be as responsive as possible.
                            this_thread::yield();
                        }

                        //Get the next character that is known to be available.
                        nextCharacter = cin.get();

                        //Check for new line character.
                        if (nextCharacter == '\n')
                        {
                            break;
                        }

                        //Since this character is not a new line character, add it to the synchronousInput string.
                        synchronousInput += nextCharacter;
                    }

                    //Be ready to stop retrieving input at any moment.
                    if (!continueGettingInput)
                    {
                        break;
                    }

                    //Wait until the processing thread is ready to process the next line.
                    while (continueGettingInput && !sendOverNextLine)
                    {
                        //Ensure that the other thread is always yielded to when necessary. Don't sleep here;
                        //only yield, in order to ensure that the processing will be as responsive as possible.
                        this_thread::yield();
                    }

                    //Be ready to stop retrieving input at any moment.
                    if (!continueGettingInput)
                    {
                        break;
                    }

                    //Safely send the next line of input over for usage in the processing thread.
                    inputLock.lock();
                    input = synchronousInput;
                    inputLock.unlock();

                    //Signal that although this thread will read in the next line,
                    //it will not send it over until the processing thread is ready.
                    sendOverNextLine = false;
                }
                while (continueGettingInput && input != "exit");
            }).detach();
        }

        //Stop getting asynchronous CLI input.
        ~AsyncGetline()
        {
            //Stop the getline thread.
            continueGettingInput = false;
        }

        //Get the next line of input if there is any; if not, sleep for a millisecond and return an empty string.
        string GetLine()
        {
            //See if the next line of input, if any, is ready to be processed.
            if (sendOverNextLine)
            {
                //Don't consume the CPU while waiting for input; this_thread::yield()
                //would still consume a lot of CPU, so sleep must be used.
                this_thread::sleep_for(chrono::milliseconds(1));

                return "";
            }
            else
            {
                //Retrieve the next line of input from the getline thread and store it for return.
                inputLock.lock();
                string returnInput = input;
                inputLock.unlock();

                //Also, signal to the getline thread that it can continue
                //sending over the next line of input, if available.
                sendOverNextLine = true;

                return returnInput;
            }
        }

    private:
        //Cross-thread-safe boolean to tell the getline thread to stop when AsyncGetline is deconstructed.
        atomic<bool> continueGettingInput;

        //Cross-thread-safe boolean to denote when the processing thread is ready for the next input line.
        //This exists to prevent any previous line(s) from being overwritten by new input lines without
        //using a queue by only processing further getline input when the processing thread is ready.
        atomic<bool> sendOverNextLine;

        //Mutex lock to ensure only one thread (processing vs. getline) is accessing the input string at a time.
        mutex inputLock;

        //string utilized safely by each thread due to the inputLock mutex.
        string input;
};

void main()
{
    AsyncGetline ag;
    string input;

    while (true)
    {
        //Asynchronously get the next line of input, if any. This function automagically
        //sleeps a millisecond if there is no getline input.
        input = ag.GetLine();

        //Check to see if there was any input.
        if (!input.empty())
        {
            //Print out the user's input to demonstrate it being processed.
            cout << "{" << input << "}\n";

            //Check for the exit condition.
            if (input == "exit")
            {
                break;
            }
        }

        //Print out a space character every so often to demonstrate asynchronicity.
        //cout << " ";
        //this_thread::sleep_for(chrono::milliseconds(100));
    }

    cout << "\n\n";
    system("pause");
}

这篇关于非阻塞std :: getline,如果没有输入,则退出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆