使用 BOOST 进程在单独的线程中读取子进程标准输出
Read child process stdout in a separate thread with BOOST process
我有一个主程序,它使用 boost 进程库生成一个打印
的子进程
Hello World !
每 5 秒显示一次标准输出。
我想 read/monitor 主进程中子进程的 stdout 可用时,以及在主程序中执行其他操作。
我已经尝试了 boost asynchronous IO
(http://www.boost.org/doc/libs/1_66_0/doc/html/boost_process/tutorial.html) 的示例,但是所有这些似乎都阻塞了主程序,直到子进程退出。
我们需要在单独的线程中读取子标准输出吗?有人可以提供一个示例,其中主程序可以同时做其他事情,而不是阻塞子程序的 stdout 吗?
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.
再看看。 Asynchronous I/O 下的所有示例应该可以帮助您 select 一种适合您的方法。
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 ?
不,您不需要。虽然您 可以 并且取决于您想要实现的目标,但这可能是最简单的事情。
同步
您未能告诉我们您希望能够做什么,所以假设您只想打印输出:
bp::child c("/bin/bash", std::vector<std::string> { "-c", "for a in {1..10}; do sleep 2; echo 'Hello World !'; done" });
c.wait();
那是同步的,所以你不能同时工作
使用 Reader 线程
这就像:
#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();
}
打印(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)
异步IO
不使用线程(好吧,只是主线程),看起来像:
#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();
}
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)
我有一个主程序,它使用 boost 进程库生成一个打印
的子进程Hello World !
每 5 秒显示一次标准输出。
我想 read/monitor 主进程中子进程的 stdout 可用时,以及在主程序中执行其他操作。
我已经尝试了 boost asynchronous IO
(http://www.boost.org/doc/libs/1_66_0/doc/html/boost_process/tutorial.html) 的示例,但是所有这些似乎都阻塞了主程序,直到子进程退出。
我们需要在单独的线程中读取子标准输出吗?有人可以提供一个示例,其中主程序可以同时做其他事情,而不是阻塞子程序的 stdout 吗?
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.
再看看。 Asynchronous I/O 下的所有示例应该可以帮助您 select 一种适合您的方法。
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 ?
不,您不需要。虽然您 可以 并且取决于您想要实现的目标,但这可能是最简单的事情。
同步
您未能告诉我们您希望能够做什么,所以假设您只想打印输出:
bp::child c("/bin/bash", std::vector<std::string> { "-c", "for a in {1..10}; do sleep 2; echo 'Hello World !'; done" });
c.wait();
那是同步的,所以你不能同时工作
使用 Reader 线程
这就像:
#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();
}
打印(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)
异步IO
不使用线程(好吧,只是主线程),看起来像:
#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();
}
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)