Read child process stdout in a separate thread with BOOST process

前端 未结 1 1303
你的背包
你的背包 2021-01-24 23:05

I have a main program that uses boost process library to spawn a child process that prints

Hello World !

on its stdout every 5 seconds.

<
相关标签:
1条回答
  • 2021-01-24 23:16

    I have tried out the examples for boost asynchronous IO (http://www.boost.org/doc/libs/1_66_0/doc/html/boost_process/tutorial.html) but all these seem to block the main program until the child process has exited.

    Look again. All the samples under Asynchronous I/O should help you select a method that works for you.

    Do we need to read the childs stdout in a separate thread ? Can someone please provide an example where the main program can do other things at the same time instead of blocking for stdout from th child ?

    No, you don't need to. Though you can and depending on what you're trying to achieve, it might be the easiest thing to do.

    Synchronous

    You failed to tell us what you want to be able to do, so let's assume you just want the output printed:

    Live On Coliru:

    bp::child c("/bin/bash", std::vector<std::string> { "-c", "for a in {1..10}; do sleep 2; echo 'Hello World !'; done" });
    c.wait();
    

    That's synchronous, so you can't do work in the meantime

    Using a Reader Thread

    That's like:

    Live On Coliru:

    #include <boost/process.hpp>
    #include <boost/process/async.hpp>
    #include <iostream>
    
    namespace bp = boost::process;
    
    int main() {
        bp::ipstream output;
        std::thread reader([&output] {
            std::string line;
            while (std::getline(output, line))
                std::cout << "Received: '" << line << "'" << std::endl;
        });
    
        bp::child c("/bin/bash",
            std::vector<std::string> { "-c", "for a in {1..10}; do sleep 2; echo 'Hello World ('$a')!'; done" },
            bp::std_out > output);
    
        while (c.running()) {
            std::this_thread::sleep_for(std::chrono::milliseconds(2793));
            std::cout << "(main thread working)" << std::endl;
        }
    
        std::cout << "(done)" << std::endl;
        c.wait();
    
        output.pipe().close();
        reader.join();
    }
    

    Prints (Live On Coliru):

    Received: 'Hello World (1)!'
    (main thread working)
    Received: 'Hello World (2)!'
    (main thread working)
    Received: 'Hello World (3)!'
    Received: 'Hello World (4)!'
    (main thread working)
    Received: 'Hello World (5)!'
    (main thread working)
    Received: 'Hello World (6)!'
    (main thread working)
    Received: 'Hello World (7)!'
    Received: 'Hello World (8)!'
    (main thread working)
    Received: 'Hello World (9)!'
    (main thread working)
    Received: 'Hello World (10)!'
    (main thread working)
    (done)
    

    Asynchronous IO

    Using no threads (well, just the main thread), could look like:

    Live On Coliru

    #include <boost/process.hpp>
    #include <boost/process/async.hpp>
    #include <boost/asio/high_resolution_timer.hpp>
    #include <iostream>
    #include <iomanip>
    
    namespace bp = boost::process;
    
    struct OtherWork {
        using clock = std::chrono::high_resolution_clock;
    
        OtherWork(boost::asio::io_context& io) : timer(io) { }
    
        void start() {
            timer.expires_at(clock::time_point::max());
            loop();
        }
    
        void stop() {
            timer.expires_at(clock::time_point::min());
        }
    
      private:
        void loop() {
            if (timer.expires_at() == clock::time_point::min()) {
                std::cout << "(done)" << std::endl;
                return;
            }
    
            timer.expires_from_now(std::chrono::milliseconds(2793));
            timer.async_wait([=](boost::system::error_code ec) {
                if (!ec) {
                    std::cout << "(other work in progress)" << std::endl;
                    start();
                } else {
                    std::cout << "(" << ec.message() << ")" << std::endl;
                }
            });
        }
    
        boost::asio::high_resolution_timer timer;
    };
    
    int main() {
        boost::asio::io_context io;
        bp::async_pipe output(io);
    
        OtherWork mainwork{io};
    
        bp::child c("/bin/bash", std::vector<std::string> { "-c", "for a in {1..10}; do sleep 2; echo 'Hello World ('$a')!'; done" },
                bp::std_out > output, io, bp::on_exit([&mainwork,&output](auto...) {
                        output.close();
                        mainwork.stop();
                    }));
    
        std::function<void()> readloop = [&,buffer=std::array<char, 32>{}]() mutable {
            output.async_read_some(bp::buffer(buffer), [&](boost::system::error_code ec, size_t transferred) {
                    if (transferred) {
                        std::cout << "Received: '";
                        while (transferred && buffer[transferred-1] == '\n') // strip newline(s)
                            --transferred;
                        std::cout.write(buffer.data(), transferred);
                        std::cout << "'" << std::endl;
                    }
    
                    if (ec)
                        std::cout << "Output pipe: " << ec.message() << std::endl;
                    else
                        readloop();
                });
        };
    
        mainwork.start();
        readloop();
        io.run();
    }
    

    Prints Live On Coliru

    Received: 'Hello World (1)!'
    (other work in progress)
    Received: 'Hello World (2)!'
    (other work in progress)
    Received: 'Hello World (3)!'
    Received: 'Hello World (4)!'
    (other work in progress)
    Received: 'Hello World (5)!'
    (other work in progress)
    Received: 'Hello World (6)!'
    (other work in progress)
    Received: 'Hello World (7)!'
    Received: 'Hello World (8)!'
    (other work in progress)
    Received: 'Hello World (9)!'
    (other work in progress)
    Received: 'Hello World (10)!'
    Output pipe: End of file
    Child exited with code=0(Success)
    (Operation canceled)
    
    0 讨论(0)
提交回复
热议问题