我看到的最引人注目的概念问题是
进程是异步的,无需添加线程来运行它们。¹
您过早地关闭了管道:
mService.run();
mStream.pipe().close();
从不会等待孩子退出的意义上说,运行不是“阻塞”。你可以wait
用来实现这一点。除此之外,您可以删除close()
呼叫。
关闭意味着您将丢失全部或部分输出。如果子进程在输出第一个数据之前需要一段时间,您可能看不到任何输出。
您正在mStream
从多个线程访问而不同步。这会调用未定义的行为,因为它会打开数据竞赛。
在这种情况下,您可以通过删除mStream.close()
前面提到的调用来消除直接问题,但您必须注意仅在初始化之后才启动读取器线程child
。
严格来说,应该对std::cout
.
您正在传递io_service
参考,但它没有被使用。只是放弃它似乎是个好主意。
的析构函数MyProcess
需要分离或加入线程。为了防止僵尸,它也需要分离或获取子 pid。
结合mStream
分离阅读器线程的生命周期并不是一个真正的选择,就像mStream
从线程中使用的那样。
让我们首先发布第一个修复程序,然后我将建议显示一些在您的示例范围内有意义的更多简化。
首次修复
我使用了一个简单的 bash 命令来模拟一个生成 1000 行的命令ping
:
Live On Coliru
#include <boost/process.hpp>
#include <thread>
#include <iostream>
namespace bp = boost::process;
/////////////////////////
class MyProcess {
bp::ipstream mStream;
bp::child mChild;
std::thread mReaderThread;
public:
~MyProcess();
void launch();
};
void MyProcess::launch() {
mChild = bp::child("/bin/bash", std::vector<std::string> {"-c", "yes ping | head -n 1000" }, bp::std_out > mStream);
mReaderThread = std::thread([&]() {
std::string line;
while (getline(mStream, line)) {
std::cout << line << std::endl;
}
});
}
MyProcess::~MyProcess() {
if (mReaderThread.joinable()) mReaderThread.join();
if (mChild.running()) mChild.wait();
}
/////////////////////////
class MyGui {
MyProcess _process;
public:
void launchProcess();
};
void MyGui::launchProcess() {
_process.launch();
// doSomethingElse();
}
int main() {
MyGui gui;
gui.launchProcess();
}
简化!
在当前模型中,线程不会拉它的重量。
我改为使用io_service
异步IO,您甚至可以通过从 GUI 事件循环内部轮询服务来取消整个线程²。
如果您要拥有它,并且由于子进程自然异步执行³,您可以简单地执行以下操作:
Live On Coliru
#include <boost/process.hpp>
#include <thread>
#include <iostream>
std::thread launch(std::string const& command, std::vector<std::string> args = {}) {
namespace bp = boost::process;
return std::thread([=] {
bp::ipstream stream;
bp::child c(command, args, bp::std_out > stream);
std::string line;
while (getline(stream, line)) {
// TODO likely post to some kind of queue for processing
std::cout << line << std::endl;
}
c.wait(); // reap PID
});
}
该演示显示与之前完全相同的输出。
¹事实上,添加线程是自找麻烦fork
² 或者可能是空闲的滴答声或类似的想法。Qt 有现成的集成(如何在 Qt4 或 GTK 等 GUI 框架中集成 Boost.Asio 主循环)
³ 在 Boost Process 支持的所有平台上