【问题标题】:Wait for a multithreading program written in C++ in java等待java中用C++编写的多线程程序
【发布时间】:2021-07-14 07:19:06
【问题描述】:

我用 C++ 编写了一个使用多线程的程序。使用 bash 脚本或类似的东西调用这个程序没问题,一切正常。现在我想用 Java 调用这个程序。这是我尝试过的 Java 代码示例:

Process v2j = new ProcessBuilder("./src/main/cpp/vcd_converter",
                 "-vcd", vcdfilePath, "-out", logfilePath).start();                     

InputStream is = v2j.getInputStream();
InputStream es = v2j.getErrorStream();

for(int i = 0; i < is.available(); i++) {
    System.out.println("Input: " + br.readLine());
}
for(int i = 0; i < es.available(); i++) {
    System.out.println("Error: " + ebr.readLine());
}
                                    
v2j.waitFor();

因此,如果我运行此代码,将发生以下情况:waitFor() 指令似乎不会真正等待“所有”线程,也许它只会等待一个。但是,java 程序执行时出错,因为它找不到由 C++ 程序生成的文件。所以waitFor() 不要等到我的 c++ 程序完成并生成文件。

输出也很奇怪。我只从std::cout 得到一个输出。这是一个例子:

std::cout << out_folder_path << "\n" << vcd_filename << "\n";
std::cout << std::flush;

这将只打印out_folder_path 输出。一个问题是:在std::cout 部分我什至不使用多线程。程序中的所有其他std::cout 也不打印。

所以我的问题是:我如何才能真正等待所有线程?我怎样才能得到我的程序的真正输出?

【问题讨论】:

  • 如果is.available() 因为 C++ 程序还没有打印任何东西而返回 0 会发生什么?我看不出这与 C++ 或 C++ 程序中的线程有什么关系。
  • 好吧,你说得对。该问题将由Java程序引起。而is.available() 不返回 0,它是打印 C++ 程序的第一个输出。
  • is.available() 不打印任何内容。它“返回对可以从此输入流读取(或跳过)的字节数的估计值,而不会被下一次调用此输入流的方法阻塞。
  • 您的问题是关于为什么 java 程序不等待所有 C++ 线程完成以及为什么您没有从 C++ 程序获得所有输出。我想让你看看你的java程序在做什么。它会检查是否有任何内容可供阅读,如果没有,它将跳转到waitFor()。你的java程序应该做的是从输入流中读取直到输入流关闭。
  • 根本不要使用available()。它会告诉您是否有可用的立即。如果从现在开始 10 毫秒打印某些内容,您的程序将被绊倒。完全避免这种方法。如果目前没有可用的输入,您想调用将 阻塞并等待 的东西。泰德的回答就是这样做的。

标签: java c++ linux multithreading


【解决方案1】:

您的程序不会从 C++ 程序获得所有输出,因为它在输入流耗尽之前不会读取。如果 C++ 程序在您的程序到达 is.available() 时没有产生任何输出,它会跳转到 waitFor

这是一种在输入流关闭之前进行读取的替代方法。它使用InputStreamReaderBufferedReader 并调用BufferedReaderreadline() 直到输入流关闭。

免责声明。我之前没有写过任何java程序,所以我不确定我是否一切都正确。不过总体思路应该可行。

var v2j = new ProcessBuilder("./src/main/cpp/vcd_converter", "-vcd", 
                             vcdfilePath, "-out", logfilePath).start();

InputStream is = v2j.getInputStream();
try(var reader = new BufferedReader(new InputStreamReader(is))) {
    String line;

    while ((line = reader.readLine()) != null) {
        System.out.println("Input: " + line);
    }
}

InputStream es = v2j.getErrorStream();
try(var reader = new BufferedReader(new InputStreamReader(es))) {
    String line;

    while ((line = reader.readLine()) != null) {
        System.out.println("Error: " + line);
    }
}

v2j.waitFor();

【讨论】:

  • 哇,谢谢,这个作品真的很好。我以为is.available()的方法是可以选择的,但似乎有问题。
  • @Chris 太棒了!不客气!我的解决方案的一个潜在问题是vcd_converter 是否会在错误流上写入很多内容。由于我的答案中的解决方案在常规输入流耗尽之前不会从错误流中读取,因此可能会导致死锁。然后,C++ 程序将等待 java 程序读取错误流,而 java 程序将等待输入流上的输入。稍后我可能会改进答案以解决此问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
  • 1970-01-01
  • 2017-10-27
相关资源
最近更新 更多