c++boostboost-process

Boost::process child by id


How I can get child.id() in on_exit function?

bp::child c(args, ios, bp::on_exit([&](int e, std::error_code ec) {
            result = e;
            ios.stop();
            //need c.id();    

        }));

or how I can check in other function if the child is running by id?

        boost::process::child c(data->id); // doesn't work
        if (!c.running()) {
}

Solution

  • You can bind whatever extra information you want to your handler. For example, you can declare your handler to take a reference to the child instance:

    static void exit_handler(bp::child& process, int e, std::error_code ec) {
        std::cout << "Process " << process.id() << " exited with " << e << " (" << ec.message() << ")\n";
    }
    

    Now, you can bind that to the on_exit handler using std::bind (of course you can use a lambda to do the job):

    p = bp::child(
            sv{"/bin/bash", "-c", command.str()},
            bp::on_exit(std::bind(exit_handler, std::ref(p), _1, _2)),
            io);
    
    // Or, using a lambda to capture the reference:
    p = bp::child(
            sv{"/bin/bash", "-c", command.str()},
            bp::on_exit([&p](int e, std::error_code ec) { exit_handler(p, e, ec); }),
            io);
    

    A full example that spawns 11 child processes that take varying time < 1s to complete and all bind to the same handler:

    Live On Coliru

    #include <boost/process.hpp>
    #include <boost/process/async.hpp>
    #include <iostream>
    #include <functional> // std::bind & placeholders
    #include <sstream>    // ostringstream
    
    namespace bp = boost::process;
    using namespace std::placeholders;
    using sv = std::vector<std::string>;
    
    static void exit_handler(bp::child& process, int e, std::error_code ec) {
        std::cout << "Process " << process.id() << " exited with " << e << " (" << ec.message() << ")\n";
    }
    
    int main() {
        boost::asio::io_context io;
        auto work = make_work_guard(io);
    
        std::list<bp::child> children;
    
        for (auto ch = 'a'; ch < 'k'; ++ch) {
            auto& p = children.emplace_back();
            std::ostringstream command;
            command << "echo 'hello from " << ch << "';";
            command << "sleep 0.$RANDOM;";
            command << "echo 'bye from " << ch << "';";
            command << "exit " << (rand()%42) << ";";
    
            p = bp::child(
                    sv{"/bin/bash", "-c", command.str()},
                    bp::on_exit(std::bind(exit_handler, std::ref(p), _1, _2)),
                    io);
        }
    
        work.reset(); // allow io to be finished
        io.run();     // wait for that
    
        std::cout << "Bye\n";
    }
    

    Prints:

    hello from b
    hello from a
    hello from c
    hello from d
    hello from e
    hello from f
    hello from g
    hello from i
    hello from h
    hello from j
    bye from g
    bye from a
    bye from h
    bye from b
    bye from d
    bye from f
    bye from j
    bye from e
    bye from i
    bye from c
    Process 12044 exited with 10 (Success)
    Process 12034 exited with 1 (Success)
    Process 12047 exited with 30 (Success)
    Process 12035 exited with 4 (Success)
    Process 12038 exited with 19 (Success)
    Process 12043 exited with 31 (Success)
    Process 12050 exited with 31 (Success)
    Process 12042 exited with 29 (Success)
    Process 12049 exited with 15 (Success)
    Process 12036 exited with 9 (Success)
    Bye
    

    UPDATE

    To also be able to query which child is still running, consider using a map instead of a list (be very careful about reference stability of your container choice!).

    Here's a demo Live On Coliru

    std::map<char, bp::child> children;
    
    for (char name = 'a'; name < 'k'; ++name) {
        std::ostringstream command;
        command << "echo 'hello from " << name << "';";
        command << "sleep " << (rand()%900 + 101)/1000.0 << ";";
        command << "echo 'bye from " << name << "';";
        command << "exit " << (rand()%42) << ";";
    
        auto& p = children[name];
        p = bp::child(
                sv{"/bin/sh", "-c", command.str()},
                bp::on_exit(std::bind(exit_handler, std::ref(p), _1, _2)),
                io);
    }
    
    work.reset(); // allow io to be finished
    
    while (io.run_one()) { // wait for that
        std::cout << "Still running: ";
        for (auto& [name, child] : children) {
            if (child.running())
                std::cout << " " << name;
        }
        std::cout << std::endl;
    }
    
    std::cout << "Bye\n";
    

    Prints

    hello from a
    hello from b
    hello from c
    hello from d
    hello from e
    hello from f
    hello from g
    hello from h
    hello from i
    Still running:  a b c d e f g h i j
    Still running:  a b c d e f g h i j
    hello from j
    bye from i
    Still running:  a b c d e f g h j
    Process 30748 exited with -1
    Still running:  a b c d e f g h j
    bye from e
    Still running:  a b c d f g h j
    Still running:  a b c d f g h j
    Process 30739 exited with -1
    Still running:  a b c d f g h j
    bye from c
    Still running:  a b d f g h j
    Still running:  a b d f g h j
    Process 30735 exited with -1
    Still running:  a b d f g h j
    bye from b
    Still running:  a d f g h j
    Still running:  a d f g h j
    Process 30733 exited with -1
    Still running:  a d f g h j
    bye from h
    Still running:  a d f g j
    Still running:  a d f g j
    Process 30744 exited with -1
    Still running:  a d f g j
    bye from d
    Still running:  a f g j
    Still running:  a f g j
    Process 30737 exited with -1
    Still running:  a f g j
    bye from g
    Still running:  a f j
    Still running:  a f j
    Process 30743 exited with -1
    Still running:  a f j
    bye from f
    Still running:  a j
    Still running:  a j
    Process 30740 exited with -1
    Still running:  a j
    bye from j
    Still running:  a
    Still running:  a
    Process 30749 exited with -1
    Still running:  a
    bye from a
    Still running: 
    Still running: 
    Process 30732 exited with -1
    Still running: 
    Bye