我有两个线程,每个启动一个subprocess。 第一个应用程序是一个运行相当长的二进制文件。 第二个退出很快。
有一个竞争条件有时会导致失败。 下面我有一个最小可行的代码示例。
它使用Boost Process 0.5,它使用标准的fork / execve / dup2系统。 有一些关于如何提升stream程工作的黑客,但总的来说,它工作得很好。
父进程启动更多的进程,并在一般情况下,它的工作。
我不能随时启动一个进程,特别是因为我不知道哪个部分不能交错。
任何想法,为什么这会挂?
预期产出:
/etc/init.d/led restart: Creating child Creating child1 Reading STDOUT /etc/init.d/led restart: Waiting for it to exit Reading std_err_pipe wait_for_exit(pullapp); Reading std_out_pipe < file list> Done
但是,经常(但并非总是)在std_err_pipe处停止。
#include <iostream> #include <string> #include <vector> #include <boost/iostreams/stream.hpp> #include <boost/process.hpp> #include <boost/thread.hpp> void run_sleep() { int exit_code; std::string str; std::vector< std::string > args; boost::shared_ptr<boost::process::child> child; args.push_back(boost::process::search_path("sleep")); args.push_back("20"); boost::iostreams::stream< boost::iostreams::file_descriptor_source > out_stream; boost::process::pipe out_pipe = boost::process::create_pipe(); { //MUST BE IN SEPARATE SCOPE SO SINK AND SOURCE ARE DESTROYED // See http://stackoverflow.com/a/12469478/5151127 boost::iostreams::file_descriptor_sink out_sink (out_pipe.sink, boost::iostreams::close_handle); boost::iostreams::file_descriptor_source out_source (out_pipe.source, boost::iostreams::close_handle); std::cout << "Creating child1" << std::endl; child.reset(new boost::process::child( boost::process::execute( boost::process::initializers::run_exe(args[0]), boost::process::initializers::set_args(args), boost::process::initializers::bind_stdout(out_sink), boost::process::initializers::bind_stderr(out_sink) ) )); out_stream.open(out_source); } std::cout << "Reading STDOUT" << std::endl; while( out_stream ) { std::string line; std::getline(out_stream, line); std::cout << line << std::endl; } std::cout << "wait_for_exit(pullapp);" << std::endl; exit_code = wait_for_exit(*child); child.reset(); return; } void run_ls() { int exit_code; std::string str; std::vector< std::string > args ; args.push_back(boost::process::search_path("ls")); args.push_back("/lib"); boost::process::pipe std_out_pipe = boost::process::create_pipe(); boost::process::pipe std_err_pipe = boost::process::create_pipe(); std::cout << "/etc/init.d/led restart: Creating child" << std::endl; { boost::process::child child = boost::process::execute( boost::process::initializers::set_args(args), boost::process::initializers::bind_stdout( boost::iostreams::file_descriptor_sink( std_out_pipe.sink, boost::iostreams::close_handle ) ), boost::process::initializers::bind_stderr( boost::iostreams::file_descriptor_sink( std_err_pipe.sink, boost::iostreams::close_handle ) ), boost::process::initializers::throw_on_error() ); std::cout << "/etc/init.d/led restart: Waiting for it to exit" << std::endl; exit_code = wait_for_exit(child); } { //with std_err_stream, istream boost::iostreams::stream< boost::iostreams::file_descriptor_source > std_err_stream( boost::iostreams::file_descriptor_source( std_err_pipe.source, boost::iostreams::close_handle ) ); std::cout << "Reading std_err_pipe" << std::endl; std::istream istream(std_err_stream.rdbuf()); while( istream ) { getline(istream, str); std::cout << str << std::endl; } } { //with std_out_stream, istream boost::iostreams::stream< boost::iostreams::file_descriptor_source > std_out_stream( boost::iostreams::file_descriptor_source( std_out_pipe.source, boost::iostreams::close_handle ) ); std::cout << "Reading std_out_pipe" << std::endl; std::istream istream(std_out_stream.rdbuf()); while( istream ) { getline(istream, str); std::cout << str << std::endl; } } std::cout << "Done" << std::endl; } int main() { boost::thread run_sleep_tr(run_sleep); boost::thread run_ls_tr(run_ls); run_sleep_tr.join(); run_ls_tr.join(); return 0; }
(保存为process-test.cpp并用g++ process-test.cpp -o process-test -lboost_iostreams -lboost_filesystem -lboost_thread -lboost_system
编译g++ process-test.cpp -o process-test -lboost_iostreams -lboost_filesystem -lboost_thread -lboost_system
)
显然这是因为文件句柄最终在多个进程中。 这些进程不关闭这些句柄,所以父母仍然在等待。
对于Linux来说,修复相对容易; 应该使用create_pipe
O_CLOEXEC
创建管道。 bind_*
方法中的dup2
调用清除了这个标志,这足以让管道正常工作。
在Windows上,我还没有真正找到解决方案。 您必须将句柄标记为可继承。 在executor()
方法中可以做到这一点,但也许这需要一个全局互斥体。 我还没有时间正确地研究它。
我不确定“使用boost.process 0.6”是否可以作为答案,但是这样做对你有帮助。 在几个错误报告之后。 在关闭父亲进程中的接收器的窗口应该足够了。