Как синхронно взаимодействовать с процессом в Boost.Process 0.5

Это вопрос о Boost.Process 0.5, а не о более поздних версиях или более ранняя версия, Boost теперь содержит библиотеку Boost.Process с другим синтаксисом и функциями.

Предположим, у меня есть простая программа, которая запрашивает число и возвращает другое число, а именно:

// ask.x,  simple program with IO
#include<iostream>
int main(){
    double n;
    std::cout << "number?" << std::endl;
    std::cin >> n;
    std::cout << n + 1 << std::endl;
}

Теперь я хочу программно взаимодействовать с этой программой с помощью Boost.Process 0.5 (http://www.highscore.de/boost/process0.5/boost_process/tutorial.html). Когда я пытаюсь использовать библиотеку, я не получаю ожидаемого поведения, номер никогда не отправляется в программу. (чтение первой строки нормально). Я попытался написать обобщение примера, описанного в http://www.highscore.de/boost/process0.5/boost_process/tutorial.html#boost_process.tutorial.synchronous_i_o, но мне это не удалось.

MWE, первая половина - это много необходимого шаблона, и я думаю, что и в этом я допустил ошибку.

#include <boost/process.hpp> // version 0.5
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <string>
#define ALSOSEND // for fully interactive case
using namespace boost;
int main() {
    // Boilerplate code, see input only example here https://stackoverflow.com/questions/12329065/how-to-bind-program-termination-with-end-of-stream-in-boost-process-0-5
    process::pipe pi = boost::process::create_pipe();
    process::pipe po = boost::process::create_pipe();
    {
        iostreams::file_descriptor_sink sink(
            pi.sink, 
            iostreams::close_handle
        );
        iostreams::file_descriptor_source source(
            po.source, 
            boost::iostreams::close_handle
        );
        process::execute(
            process::initializers::run_exe("./ask.x"), 
            process::initializers::bind_stdout(sink)
    #ifdef ALSOSEND
            , process::initializers::bind_stdin(source)
    #endif
        );
    }

    iostreams::file_descriptor_source fdsource(pi.source,  iostreams::close_handle);
    iostreams::stream<iostreams::file_descriptor_source> is(fdsource);
    iostreams::file_descriptor_sink fdsink(po.source,  iostreams::close_handle);
    iostreams::stream<iostreams::file_descriptor_sink> os(fdsink);

    // actual interaction with the process
    std::string line;
    std::getline(is, line);
    assert(line == "number?");
    std::cout << "sending: " << "5" << std::endl;
    os << "5" << std::endl; // RUN GETS STUCK HERE
    std::getline(is, line);
    assert(line == "6");
}

Очевидно, я не понимаю логику стоков и источников. Я также пробовал использовать один pipe для приемника и источника, но это не сработало.

Как сделать так, чтобы программа выполняла и чтение, и запись из исполняемого проекта и в него?

Я не могу найти пример, в котором чередуются вход и выход.


ИЗМЕНИТЬ, чтобы показать рабочий пример с более ранней версией библиотеки

Так это делалось в Boost.Process GSOC2010 (не 0,5, как в вопросе выше), обратите внимание, что фактическое взаимодействие с программой такое же, как указано выше.

#include <boost/filesystem.hpp> // quasibug in process GSOC2010 needs to include filesystem BEFORE
#include <boost/process.hpp> // version GSOC2010 (not 0.5)
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <string>

using namespace boost;
int main() {
    // boiler plate code
    std::vector<std::string> args;
    process::context ctx;
    ctx.process_name       = "askprocess";
    ctx.streams[process::stdout_id] = boost::process::behavior::pipe();
    ctx.streams[process::stdin_id ] = boost::process::behavior::pipe();

    process::child c = create_child("./ask", args, ctx);
    process::pistream is(c.get_handle(process::stdout_id));
    process::postream os(c.get_handle(process::stdin_id ));

    // actual interaction with the process
    std::string line;
    std::getline(is, line);
    assert(line == "number?");
    std::cout << "sending: " << "5" << std::endl;
    os << "5" << std::endl; // RUN GETS STUCK HERE
    std::getline(is, line);
    assert(line == "6");
}

person alfC    schedule 02.04.2015    source источник
comment
Улучшенные версии (у вас были запутанные копии объектов устройства): test.cpp, child.cpp. Он работает несколько раз, но я не нашел, как заставить его работать надежно   -  person sehe    schedule 02.04.2015
comment
Иногда это срабатывает? :(. Я только что скопировал ваш код, и он с самого начала зависает (не печатает даже первую строку). Boost 1.55, gcc 4.9.2, (или clang 3.5), Fedora 22. Очень грустно. Я снова должен вернуться в Boost.Process 0.3.   -  person alfC    schedule 02.04.2015
comment
Здесь: ubuntu, boost 1.57, gcc 4.8.2. Вы имеете в виду, что это работает в BP0.3?   -  person sehe    schedule 02.04.2015
comment
@sehe, Нет, в Boost.Process 0.3 код совсем другой (без boost.iostream, стоков и тд) и чего-то с этой целью было легко добиться. Кстати, не связанная с этим вещь, мы недавно определили, что приемник должен выходить из области видимости сразу после выполнения, чтобы вести себя хорошо stackoverflow.com/questions/ 12329065 /   -  person alfC    schedule 02.04.2015
comment
@sehe, я добавил и отредактировал в конце полный код, который он использовал для работы с Boost.Process GSOC2010. Это выглядело проще (хотя все еще довольно много шаблонов, подверженных ошибкам), и, кроме того, он работает так, как ожидалось (компилируется, запускается и хорошо взаимодействует). Возможно, я ошибаюсь, пытаясь использовать Boost.Process 0.5 синхронно, возможно, библиотека разработана с учетом асинхронного использования (к чему я не привык).   -  person alfC    schedule 03.04.2015


Ответы (1)


Похоже, это опечатка в следующей строке:

iostreams::file_descriptor_sink fdsink(po.source,  iostreams::close_handle);

Должно быть:

iostreams::file_descriptor_sink fdsink(po.sink,  iostreams::close_handle);
person Serge Medvedev    schedule 11.04.2016