Состояние гонки при запуске подпроцессов приводит к зависанию чтения из канала

У меня есть два потока, которые запускают дочерний процесс каждый. Первое приложение — это двоичный файл, который работает довольно долго. Второй выходит довольно быстро.

Существует состояние гонки, которое иногда приводит к сбою. Ниже у меня есть пример минимального жизнеспособного кода.

Он использует 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_pipewait_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)

0

Решение

Видимо, это потому, что файловые дескрипторы заканчиваются в нескольких процессах. Эти процессы не закрывают эти дескрипторы, поэтому родитель остается в ожидании.

Для Linux исправление относительно легкое; труба должна быть создана с O_CLOEXEC в create_pipe, dup2 позвонить в bind_* Методы сбрасывают этот флаг, что достаточно для правильной работы канала.

В Windows я пока не нашел решения. Вы должны пометить дескриптор как наследуемый. Это может быть возможно сделать в executor() метод, но, возможно, это требует глобального мьютекса. У меня еще не было времени, чтобы как следует разобраться.

0

Другие решения

Я не уверен, что «использовать boost.process 0.6» считается ответом, но это делает это для вас. После нескольких сообщений об ошибках это.
На окнах, закрывающих мойку, в отцовском процессе должно хватить.

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector