Как связать завершение программы с концом потока в Boost.Process 0.5?

В этом простом примере Boost.Process 0.5 ( http://www.highscore.de/boost/process0.5/index.html) вывод программы (lsподает поток. Поток работает нормально, но вопреки ожиданиям поток не становится недействительным (например, конец потока) после завершения программы (аналогично предыдущей версии Boost.Process, например, http://www.highscore.de/boost/process/index.html)

Чего мне не хватает, чтобы сделать стрим (is в примере) автоматически становится недействительным после выхода из дочерней программы?

Возможно, это опция, которую я должен установить в Boost.Streams stream из file_descriptor?

#include <boost/process.hpp> // version 0.5 from http://www.highscore.de/boost/process0.5/process.zip
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <string>
using namespace boost::process;
using namespace boost::process::initializers;
using namespace boost::iostreams;
int main(){
boost::process::pipe p = create_pipe();
file_descriptor_sink sink(p.sink, close_handle);
child c = execute(run_exe("/usr/bin/ls"), bind_stdout(sink));
file_descriptor_source source(p.source,  close_handle);
stream<file_descriptor_source> is(source);
std::string s;
while(std::getline(is, s)){
std::cout << "read: " << s << std::endl;
}
std::clog << "end" << std::endl; // never reach
}

11

Решение

У меня было личное (на самом деле через Наббл) общение с Борисом Шаилингом, автором библиотеки. Отбросив несколько возможностей, таких как ошибки в posix / boost.iostreams, он дал мне небольшую модификацию работающего кода. По сути, я могу сделать вывод, что file_descriptor sink должен быть вне области (уничтожен), чтобы поток возвращал EOF. Рабочий код просто добавляет определенную область для sink (указано в конце). Я думаю, что это позволяет легко заключить все в pistream вид класса. (Следующим шагом в моем списке будет также разрешить вывод в процесс.)

Работает с Boost 1.48 (Fedora 17).

#include <boost/process.hpp> // version 0.5
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <string>

using namespace boost::process;
using namespace boost::process::initializers;
using namespace boost::iostreams;

int main() {
pipe p = create_pipe();
{
// note the scope for sink
file_descriptor_sink sink(p.sink, close_handle);
/*  child c = */ // not necessary to hold a child object, it seems.
execute(run_exe("/usr/bin/ls"), bind_stdout(sink));
}   // note the scope for sink

file_descriptor_source source(p.source,  close_handle);
stream<file_descriptor_source> is(source);
std::string s;
while(std::getline(is, s)) {
std::cout << "read: " << s << std::endl;
}
std::clog << "end" << std::endl; // never reach
}

Компилируется с c(lang)++ -lboost_system -lboost_iostreams

РЕДАКТИРОВАТЬ: Это, кажется, работает, что позволяет избежать искусственного объема, но может сбить с толку, потому что приемник должен быть временным:

    ...
pipe p = create_pipe();
execute(run_exe("/usr/bin/ls"), bind_stdout(
file_descriptor_sink(p.sink, close_handle)
));
file_descriptor_source source(p.source,  close_handle);
...
4

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

Это работает на POSIX-подобных системах:

#include <boost/process.hpp> // version 0.5 from http://www.highscore.de/boost/process0.5/process.zip
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/asio.hpp>
#include <string>

using namespace boost::process;
using namespace boost::process::initializers;
using namespace boost::iostreams;

int main()
{
boost::asio::io_service io_service;
int status = 1;
boost::asio::signal_set set(io_service, SIGCHLD);
set.async_wait(
[&status](const boost::system::error_code&, int) { ::wait(&status); }
);

boost::process::pipe p = create_pipe();
file_descriptor_sink sink(p.sink, close_handle);
child c = execute(run_exe("/bin/ls"), bind_stdout(sink));
file_descriptor_source source(p.source,  close_handle);
stream<file_descriptor_source> is(source);
std::string s;
while(status && std::getline(is, s))
{
std::cout << "read: " << s << std::endl;
}
std::clog << "end" << std::endl; // never reach
}

Обратите внимание, что он обрабатывает SIGCHLD для асинхронно задавать status, Это было взято из http://www.highscore.de/boost/process0.5/boost_process/tutorial.html#boost_process.tutorial.starting_a_program. Эта страница также показывает стиль Windows, делающий то же самое:

#if defined(BOOST_WINDOWS_API)
DWORD exit_code;
boost::asio::windows::object_handle handle(io_service, c.process_handle());
handle.async_wait(
[&handle, &exit_code](const boost::system::error_code&)
{ ::GetExitCodeProcess(handle.native(), &exit_code); }
);
#endif

io_service.run();
3