Как да взаимодействаме синхронно с процес в 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