非阻塞从std :: cin工作与std :: this_thread :: sleep_for()或std :: this_thread :: yield()(IPC) [英] Does non-blocking read from std::cin work with std::this_thread::sleep_for() or std::this_thread::yield() (IPC)

查看:960
本文介绍了非阻塞从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();
}



我还尝试用yield()

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

在我看来,这段代码应该工作如下:我偷看std :: cin。如果有东西,我从cin读。



我知道,屈服被认为不是一个非常干净的工作方式,但我想保持沟通在这两个应用程序之间尽可能简单。没有第三方库,如果可能,没有更复杂的概念(如Sockets)。



然而,这种方法不工作,它提供与第一种方法相同的行为只是从std :: cin读入。 Java程序变得无响应,并且这两个应用程序都没有做任何事情。



如果在shell中调用C ++应用程序,并且如果我提供相同的输入键盘,所以问题不应该存在。如果我从C ++应用程序中删除所有这些给定的代码片段,Java应用程序是响应和工作 - 虽然它没有得到它需要的输入,显然。

在尝试了很长时间来实现cin的非阻塞输入后,我确定不可能让它工作一致。



我已经简化了我的实现一点点为这个例如,您需要某种线程安全的存储系统。

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

//超简单线程安全存储
std :: queue< std :: string>数据库;
std :: mutex Padlock;
void PushLine(std :: string Line){
std :: unique_lock< std :: mutex>锁定(挂锁); (void)Lock;
Database.push(Line);
}
bool IsLineAvailable(void){
std :: unique_lock< std :: mutex>锁定(挂锁); (void)Lock;
return!Database.empty();
}
std :: string PopLine(void){
std :: unique_lock< std :: mutex>锁定(挂锁); (void)Lock;
std :: string Line(std :: move(Database.back()));
Database.pop();
return Line;
}

//从cin
输入的非阻塞的主函数int main(int argc,char * argv []){
(void) argc;
(void)argv;
std :: thread InputThread = std :: thread([](){
do {
//确保输入尽可能干净
if(std :: cin .rdbuf() - > in_avail()){
std :: cin.ignore(std :: cin.rdbuf() - > in_avail());
}
std: :cin.clear();

//获取一行,cin会阻塞这里
std :: string Line;
std :: getline(std :: cin, Line);

//如果行不为空,尝试存储它
if(!Line.empty()){
PushLine(Line);
}
} while(1);
});

//从线程分离,它永远不会结束。
InputThread.detach();

//一个工作要做。
unsigned int Counter = 0;

//运行你的程序。
bool Running = true;
while(Running){
//执行作业,在这种情况下计数。
Counter ++;

//检查可用的输入
if(IsLineAvailable()){
//如果有输入可用,首先获取
std :: string Line = PopLine();

//回送到终端
std :: cout<< Command:<<线<< std :: endl;

//根据命令执行操作
if(Line ==quit){
Running = false;
}
else if(Line ==count){
std :: cout< Count:<计数器<< std :: endl;
}
}

//睡眠一会儿
std :: this_thread :: sleep_for(std :: chrono :: milliseconds(100));
}

//完成。
return 0;
}


I've encountered a specific problem with my implementation and can't find a solution for it.

I have a two-part application. One part is a Java swing GUI. The second part is a C++ application that does all the (time consuming) calculation logic. The two processes communicate (in both directions) with their output and input streams. My problem now is that in one part of the C++ program I have to wait for user input coming from the Java program. However, waiting seems to block.

What works perfectly when I call the program in a shell is:

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

When working with the Java UI, this does not work (naturally), because reading from std::cin is blocking, so when the C++ application waits for input, the Java application can't do anything.

Therefore I made another way of reading from std::cin that should (at least in my mind) work, but I can't make it work. It is:

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

I also tried to replace the line with yield() with

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

In my mind, this code should work as following: I peek on std::cin. If something is there, I read it from cin. If nothing is there, I yield and try again later.

I know, yielding is considered to not be a very clean way of working, but I want to keep the communication between those two applications as simple as possible. No third party libraries, no more complex concepts (as Sockets), if possible.

However, this approach doesn't work, it gives the same behaviour as the first approach with just reading in from std::cin. The Java program becomes unresponsive and none of the two applications seem to do anything.

The C++ application works perfectly if called in a shell and if I provide the same input from the keyboard, so the problem shouldn't be there. If I delete all these given code snippets from the C++ application, the Java application is responsive and works - although it doesn't get the input it needs, obviously.

解决方案

After trying for a long time to implement non-blocking input from cin, I'm pretty sure it's impossible to getting it to work consistently.

My current solution is to put the blocking cin into it's own tiny thread and let it do it's thing.

I've simplified my implementation a little bit for this example, as you need a thread safe storage system of some kind.

#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;
}

这篇关于非阻塞从std :: cin工作与std :: this_thread :: sleep_for()或std :: this_thread :: yield()(IPC)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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