2013-05-16 13 views
10

Hiện tại tôi có một chương trình đọc từ đầu vào chuẩn, đôi khi chương trình cần tiếp tục chạy nếu không có đầu vào nào, thường là tập lệnh thử nghiệm không có 'nhập' để nói.std không chặn :: getline, thoát nếu không có đầu vào

program -v1 -v2 -v3 <input >output

v1 - v3 là đối số dòng lệnh tương ứng

Về cơ bản các chương trình spits ra các đối số dòng lệnh và ý nghĩa tương ứng của họ đối với chương trình nếu không có 'đầu vào' được đưa ra và sau đó nên thoát.

Tuy nhiên tại thời điểm này, nếu cho nó một tệp kiểm tra trống hoặc chỉ chạy mà không cần nhấn enter sau khi chạy nó chặn trên std :: getline tôi sử dụng để nhập lệnh.

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

trong đó foo là một chuỗi.

Làm cách nào để chạy ứng dụng và chỉ cần chạy qua và do stuff ít nhất một lần rồi thoát ra trong trường hợp không có đầu vào? Trong trường hợp đầu vào, do stuff xảy ra một lần cho mỗi dòng trong đầu vào tiêu chuẩn.

Có chuyển đổi sang vòng lặp do-while hay không, với vòng lặp kiểm tra xem liệu nó có đầu vào, hoạt động không?

Something như

if cin empty 
set flag 

do 
{do stuff 
check flag} 
while(getline) 

hoặc là non-blocking io không thể trong C++?

Câu hỏi này dường như được phục hồi nhiều lần nhưng tôi không thể tìm thấy câu trả lời dứt khoát hoặc thậm chí câu trả lời là nền tảng bất khả tri (chương trình này có tính chất học thuật, được mã hóa trên cửa sổ và được kiểm tra trên Unix).

+0

vì vậy bạn có nói rằng bạn muốn vòng lặp chạy một lần bất kể điều gì, sau đó thoát ra nếu không có đầu vào nào được đưa ra trước cuộc gọi getline? –

+0

có thể trùng lặp của [kiểm tra tính khả dụng của dữ liệu trước khi gọi std :: getline] (http://stackoverflow.com/questions/3317740/checking-data-availability-before-calling-stdgetline) Thật không may, có lẽ không phải là một cách di động để làm điều này trong tiêu chuẩn C++. – jrok

+0

Bạn có thể sử dụng một số chức năng cấp thấp từ C không? – Zaffy

Trả lời

1

Bạn có thể sử dụng cin.peek để kiểm tra xem có điều gì cần đọc hay không và sau đó gọi getline nếu có. Mặc dù vậy, chẳng có thứ gì như là đường cấm không bị chặn.

+3

Điều đó cũng sẽ chặn nếu không có sẵn dữ liệu đầu vào. – jrok

+0

như trên các khối cin.peek là tốt, tôi đã cố gắng. –

+0

'cin.peek' nên chặn bởi vì, theo tiêu chuẩn: _Returns: traits :: eof() nếu good() là false. Nếu không, trả về rdbuf() -> sgetc() _ Vì vậy, theo như tôi hiểu nó không nên có thể sử dụng 'peek()' để kiểm tra luồng trong cách bỏ chặn. –

5

Sử dụng std :: cin không đồng bộ có thể là cách duy nhất để thực hiện công việc này, vì iostream không được thiết kế để có hành vi không chặn. Dưới đây là một ví dụ:

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

Mã này được nhận xét vì thế nên dễ hiểu. Đó là một lớp an toàn cho phép bạn không đồng bộ nhận được một dòng bằng cách sử dụng std :: cin.

Rất dễ sử dụng cho mục đích getline CLI không đồng bộ, với mức sử dụng CPU 0% trên máy tính của tôi. Nó hoạt động hoàn toàn tốt trên Windows 10 trong Visual Studio 2015 c + + Win32 Console Debug và chế độ phát hành. Nếu nó không hoạt động trong hệ điều hành hoặc môi trường của bạn, điều đó quá tệ.

#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

Xin chào, tôi đã dành rất nhiều công sức cho việc này và nó hoạt động tốt và có ý kiến ​​rất hay. Tại sao downvote? – Andrew

+2

Tôi không chắc chắn lý do tại sao điều này đã được bình chọn, nhưng đây là một upvote! –