从std :: cin读取的非阻塞是否适用于std :: this_thread :: sleep_for()或std :: this_thread :: yield()(IPC)

时间:2015-10-11 16:31:09

标签: java c++ asynchronous parallel-processing 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();
}

我还试图用

替换yield()行
std::this_thread::sleep_for(std::chrono::milliseconds(500));

在我看来,这段代码应该如下:我看一下std :: cin。如果有什么东西,我从cin读到它。如果没有,我会屈服并稍后再试。

我知道,屈服被认为不是一种非常干净的工作方式,但我希望尽可能简化这两个应用程序之间的沟通。如果可能的话,没有第三方库,没有更复杂的概念(如套接字)。

然而,这种方法不起作用,它提供了与第一种方法相同的行为,只需从std :: cin读入。 Java程序没有响应,两个应用程序似乎都没有做任何事情。

如果在shell中调用C ++应用程序是完美的,如果我从键盘提供相同的输入,那么问题就不应该存在。如果我从C ++应用程序中删除所有这些给定的代码片段,Java应用程序就会响应并且有效 - 尽管它显然无法获得所需的输入。

1 个答案:

答案 0 :(得分: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.front()));
    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;
}