2013-05-16 13 views
10

Attualmente ho un programma che legge dallo standard input, a volte il programma deve semplicemente continuare a funzionare se non viene fatto alcun input, di solito questo è uno script di test non c'è 'inserisci' per così dire.std :: getline senza uscita, uscita se nessun input

program -v1 -v2 -v3 <input >output

v1 - v3 sono argomenti della riga di comando rispettivamente

Fondamentalmente il programma sputa fuori gli argomenti della riga di comando e il loro rispettivo significato al programma se non viene dato 'ingresso' e quindi dovrebbe uscire.

Tuttavia al momento se gli danno un file di test vuoto o semplicemente si esegue senza premere invio dopo aver eseguito il blocco su std :: getline che uso per inserire i comandi.

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

dove foo è una stringa.

Come faccio a farlo funzionare solo attraverso e do stuff almeno una volta quindi l'uscita in caso di nessun input? In caso di ingresso do stuff si verifica una volta per ogni linea di input standard.

Sarebbe un passaggio a un ciclo do-while, con un assegno ciclo pre sul fatto che è ottenuto alcun input, lavorare?

Qualcosa di simile

if cin empty 
set flag 

do 
{do stuff 
check flag} 
while(getline) 

o non è bloccante non io possibile in C++?

Questa domanda sembra essere rimaneggiata ancora e ancora ma non sono riuscito a trovare una risposta definitiva o addirittura una risposta che fosse indipendente dalla piattaforma (questo programma è di natura accademica, codificato su Windows e testato su Unix).

+0

quindi stai dicendo che vuoi eseguire il ciclo una volta non importa quale, quindi uscire se non viene dato alcun input prima di una chiamata getline? –

+0

possibile duplicato di [verificare la disponibilità dei dati prima di chiamare std :: getline] (http://stackoverflow.com/questions/3317740/checking-data-availability-before-calling-stdgetline) Sfortunatamente, probabilmente non esiste un modo portabile per farlo in C++ standard. – jrok

+0

si può utilizzare alcune funzioni di basso livello da C? – Zaffy

risposta

1

È possibile utilizzare cin.peek per verificare se c'è qualcosa da leggere, e quindi chiamare getline se c'è. Tuttavia non esiste una linea di demarcazione non bloccante.

+3

Che ti bloccano, anche se non c'è avaliable ingresso. – jrok

+0

blocchi cin.peek come sopra così, ho provato. –

+0

'cin.peek' dovrebbe bloccare perché, in base allo standard: _Returns: tratti :: eof() se good() è false. In caso contrario, restituisce rdbuf() -> sgetc() _ Quindi, per quanto ho capito, non dovrebbe essere possibile usare 'peek()' per controllare il flusso in modo sbloccante. –

5

L'utilizzo di std :: cin asincronicamente potrebbe essere l'unico modo per farlo funzionare, poiché iostream non è progettato per avere un comportamento non bloccante. Ecco un esempio:

Async Example 1 Async Example 2 (printing a space out every 1/10th of a second while accepting CLI input at the same time)

Il codice è commentato e quindi dovrebbe essere facile da capire. È una classe thread-safe che ti consente di ottenere in modo asincrono una linea usando std :: cin.

Molto facile da utilizzare per scopi di linea CLI asincroni, con utilizzo CPU pari allo 0% sul computer. Funziona perfettamente su Windows 10 in Visual Studio 2015 c + + modalità di debug della console Win32. Se non funziona nel tuo sistema operativo o ambiente, è troppo brutto.

#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.) 
//Created 02-15-17 by Andrew Davis, the creator of a new programming language called Basik. 
//If you like this code, please check it out, thanks! http://thecodingwebsite.com 
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"); 
} 
+3

Ehi, ci ho lavorato molto, e funziona bene e ha dei commenti molto positivi. Perché downvote? – Andrew

+2

Non sono sicuro del motivo per cui questo è stato downvoted, ma ecco un upvote! –