У меня есть два потока, которые запускают дочерний процесс каждый. Первое приложение представляет собой двоичный файл, который работает довольно долго. Второй выход довольно быстро.Состояние гонки при запуске подпроцессов вызывает чтение из трубы для зависания
Состояние гонки, которое иногда приводит к сбою. Ниже приведен пример минимального жизнеспособного кода.
В нем используется Boost Process 0.5, который использует стандартную систему fork/execve/dup2. Есть некоторые хаки о том, как работает Boost Process, но в целом он работает достаточно хорошо.
Родительский процесс запускает намного больше процессов, и в целом он работает.
Я не могу легко загружать процессы по одному, тем более, что я не знаю, какие части не могут чередовать.
Любые идеи о том, почему это виснет?
Ожидаемый результат:
/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;
}
(Сохранить как процесс-test.cpp и компилировать с g++ process-test.cpp -o process-test -lboost_iostreams -lboost_filesystem -lboost_thread -lboost_system
)
Очевидно, что процесс Boost, который я использовал, был старой версией. Последнее находится на странице https://github.com/klemens-morgenstern/boost-process. –