2015-10-11 69 views
1

一起工作我遇到了一個特定的問題與我的實現,找到一個解決方案。從std :: cin讀取非阻塞讀取與std :: this_thread :: sleep_for()或std :: this_thread :: yield()(IPC)

我有一個兩部分的應用程序。一部分是Java swing GUI。第二部分是一個C++應用程序,它執行所有(耗時的)計算邏輯。這兩個進程與其輸出和輸入流進行通信(在兩個方向上)。我現在的問題是,在C++程序的一部分中,我必須等待來自Java程序的用戶輸入。然而,等待似乎阻止。

什麼完美的作品,當我在一個shell調用的程序是:

std::string inputLine1; 
std::cin >> inputLine1; 

當使用Java UI的工作,這不起作用(自然),因爲從給std :: cin讀阻塞,所以當C++應用程序等待輸入時,Java應用程序無法執行任何操作。

因此,我做了另一種閱讀std :: cin的方式,應該(至少在我的腦海裏)工作,但我不能讓它工作。它是:

std::string inputLine1; 
while (true) 
{ 
    int c = std::cin.peek(); 
    if (c != EOF) 
    { 
     std::cin >> inputLine1; 
     break; 
    } 
    std::this_thread::yield(); 
} 

我也試圖與

std::this_thread::sleep_for(std::chrono::milliseconds(500)); 

在我的腦海裏,以取代與產量()行,此代碼應爲以下工作:我偷看上的std :: CIN。如果有東西在那裏,我從cin讀取它。如果什麼都沒有,我會屈服,稍後再試。

我知道,yielding被認爲不是一種非常乾淨的工作方式,但我希望儘可能簡單地保持這兩個應用程序之間的通信。如果可能的話,不需要第三方庫,也不需要更復雜的概念(如套接字)。

但是,這種方法不起作用,它只是從std :: cin中讀取第一種方法時的行爲。 Java程序變得無法響應,兩個應用程序都沒有任何操作。

如果在shell中調用C++應用程序,並且如果我從鍵盤提供相同的輸入,那麼C++應用程序將完美工作,所以問題不應該存在。如果我從C++應用程序中刪除了所有這些給定的代碼片段,那麼Java應用程序可以做出響應並且可以正常工作 - 顯然,它沒有得到所需的輸入。

+1

你正在解決這個錯誤的結局。讓C++代碼阻塞,並將Java程序中的I/O從事件循環移出到單獨的線程中。 – EJP

+0

C++''iostreams'庫看起來並沒有使用* non-blocking *編寫。我可以通過使用std :: ios :: sync_with_stdio(false);從'stdio'中解耦* ios *來實現*非阻塞*讀操作,然後使用'std :: cin.rdbuf( ) - > in_avail()'但我很確定這種行爲是依賴於實現的。 – Galik

回答

0

在嘗試了很長時間來實現來自cin的非阻塞輸入之後,我非常肯定它不可能一致地工作。

我現在的解決方案是將阻塞cin放入它自己的小線程中,讓它做到這一點。

這個例子我簡化了一下我的實現,因爲你需要一個線程安全的存儲系統。

#include <iostream> 
#include <thread> 
#include <mutex> 
#include <queue> 

// Super simple thread safe storage 
std::queue<std::string> Database; 
std::mutex Padlock; 
void PushLine(std::string Line) { 
    std::unique_lock<std::mutex> Lock(Padlock); (void)Lock; 
    Database.push(Line); 
} 
bool IsLineAvailable(void) { 
    std::unique_lock<std::mutex> Lock(Padlock); (void)Lock; 
    return !Database.empty(); 
} 
std::string PopLine(void) { 
    std::unique_lock<std::mutex> Lock(Padlock); (void)Lock; 
    std::string Line(std::move(Database.back())); 
    Database.pop(); 
    return Line; 
} 

// Main function with "non-blocking" input from cin 
int main(int argc, char *argv[]) { 
    (void)argc; 
    (void)argv; 
    std::thread InputThread = std::thread([](){ 
     do { 
      // Ensure the input is as clean as possible 
      if (std::cin.rdbuf()->in_avail()) { 
       std::cin.ignore(std::cin.rdbuf()->in_avail()); 
      } 
      std::cin.clear(); 

      // Get a line, cin will block here. 
      std::string Line; 
      std::getline(std::cin, Line); 

      // If the line is not empty attempt to store it. 
      if (!Line.empty()) { 
       PushLine(Line); 
      } 
     } while (1); 
    }); 

    // Detach from the thread, it will never end. 
    InputThread.detach(); 

    // A job to do. 
    unsigned int Counter = 0; 

    // Run your program. 
    bool Running = true; 
    while(Running) { 
     // Perform a job, in this case counting. 
     Counter++; 

     // Check for available input 
     if (IsLineAvailable()) { 
      // If there is input available, first get it 
      std::string Line = PopLine(); 

      // Echo it to the terminal 
      std::cout << "Command: " << Line << std::endl; 

      // Perform actions based on the command 
      if (Line == "quit") { 
       Running = false; 
      } 
      else if (Line == "count") { 
       std::cout << " Count: " << Counter << std::endl; 
      } 
     } 

     // Sleep for a while 
     std::this_thread::sleep_for(std::chrono::milliseconds(100)); 
    } 

    // Done. 
    return 0; 
} 
相關問題