如何通过 boost 子进程的异步 运行 测试实例计数器?
How to test an instance counter by asynchronous run of a boost childprocess?
我已尝试将 boost::childprocess 与 async_pipe 一起使用,如下面的代码示例所示,同时期望因为有等待方法,所以对 运行 的调用不会等待被调用的可执行文件完成后再继续到我调用 wait() 的行。我的目标是多次启动同一个可执行文件,以便在 GTest 中测试实例计数方法(基于 boost 管理的共享内存段实现)。
但在此之前我需要调用 io_service::运行(),而不是等待被调用的可执行文件完成现在。有人可以告诉我我在哪里使用错了吗?或者如果这是对我的功能进行单元测试的错误方法?我一直在努力寻找解决方案!
这是我如何调用可执行文件的一个实例的示例:
int CallChildProcess_Style9() {
std::string strCmdLine = "E:\file.exe --Debug MainStartUps_Off --Lock 3";
boost::asio::io_service m_oIOS;
std::vector<char> m_oAsyncBuffer_Out;
bp::async_pipe m_oAsyncPipe_Out(m_oIOS);
std::error_code build_ec;
size_t nReadSize(0);
boost::scoped_ptr<boost::process::child> m_pChildProcess(nullptr);
m_pChildProcess.reset(new bp::child(strCmdLine.data(), bp::std_out > m_oAsyncPipe_Out, build_ec));
m_oAsyncBuffer_Out.resize(1024*8);
boost::asio::async_read(m_oAsyncPipe_Out, boost::asio::buffer(m_oAsyncBuffer_Out),
[&](const boost::system::error_code &ec, std::size_t size) { nReadSize = size; });
size_t iii = m_oIOS.run();
m_pChildProcess->wait();
m_oAsyncBuffer_Out.resize(nReadSize);
std::string strBuf(m_oAsyncBuffer_Out.begin(), m_oAsyncBuffer_Out.begin() + nReadSize);
int result = m_pChildProcess->exit_code();
m_oAsyncPipe_Out.close();
m_oIOS.reset();
return result;
}
使用io_service
要使用 async_pipe
,您需要将 io_service
实例提供给 bp::child
的参数关键字:
#include <boost/asio.hpp>
#include <boost/process.hpp>
#include <boost/process/async.hpp>
#include <boost/scoped_ptr.hpp>
#include <iostream>
namespace bp = boost::process;
int CallChildProcess_Style9() {
std::string strCmdLine = "/bin/cat";
boost::asio::io_service m_oIOS;
std::vector<char> m_oAsyncBuffer_Out;
bp::async_pipe m_oAsyncPipe_Out(m_oIOS);
std::error_code build_ec;
size_t nReadSize(0);
boost::scoped_ptr<boost::process::child> m_pChildProcess(nullptr);
std::vector<std::string> const args = { "/home/sehe/Projects/Whosebug/test.cpp" };
m_pChildProcess.reset(new bp::child(strCmdLine, args, bp::std_out > m_oAsyncPipe_Out, build_ec, m_oIOS));
std::cout << "Launched: " << build_ec.message() << std::endl;
m_oAsyncBuffer_Out.resize(1024 * 8);
boost::asio::async_read(m_oAsyncPipe_Out, boost::asio::buffer(m_oAsyncBuffer_Out),
[&](const boost::system::error_code &ec, std::size_t size) {
std::cout << "read completion handler: size = " << size << " (" << ec.message() << ")" << std::endl;
nReadSize = size;
});
std::cout << "read started" << std::endl;
size_t iii = m_oIOS.run();
std::cout << "io_service stopped" << std::endl;
std::cout << "initiate child::wait" << std::endl;
m_pChildProcess->wait();
std::cout << "wait completed" << std::endl;
std::string const strBuf(m_oAsyncBuffer_Out.data(), nReadSize);
int result = m_pChildProcess->exit_code();
m_oAsyncPipe_Out.close();
m_oIOS.reset();
return result;
}
int main() {
CallChildProcess_Style9();
}
版画
http://coliru.stacked-crooked.com/a/8a9bc6bed3dd5e0a
Launched: Success
read started
read completion handler: size = 1589 (End of file)
io_service stopped
initiate child::wait
wait completed
挂断 Child
即使已修复,async_pipe::async_read
也只会读取直到缓冲区已满或达到 EOF。如果 child 进程输出超过缓冲区大小(在您的示例中为 8k),那么它将卡住并且永远不会完成。
例如:像这样替换命令:
std::string strCmdLine = "/usr/bin/yes";
结果
生活在 Coliru
Launched: Success
read started
read completion handler: size = 8192 (Success)
io_service stopped
initiate child::wait
它将挂到无穷大。这是 而不是 因为 yes
有无限输出。任何具有大输出的命令都会挂起(例如 /bin/cat /etc/dictionaries-common/words
以相同的方式挂起)。您可以通过查看 strace 输出来证明这一点:
$ sudo strace -p $(pgrep yes)
strace: Process 21056 attached
write(1, "/home/sehe/Projects/stackoverflo"..., 8170
"fix"最简单的方法是在填满输出缓冲区后关闭输出接收器:
boost::asio::async_read(m_oAsyncPipe_Out, boost::asio::buffer(m_oAsyncBuffer_Out),
[&](const boost::system::error_code &ec, std::size_t size) {
std::cout << "read completion handler: size = " << size << " (" << ec.message() << ")" << std::endl;
nReadSize = size;
m_oAsyncPipe_Out.close();
});
这要求您在调用 wait()
之前预计 child 已退出,因此 wait()
可能会失败:
Launched: Success
read started
read completion handler: size = 8192 (Success)
io_service stopped
initiate child::wait
wait completed (Success)
退一步:您需要什么?
不过,看起来您可能把问题复杂化了。如果您乐于将输出限制为 8k,并且您所需要的只是拥有多个副本,那么为什么还要使用 async io?
任何child
已经是异步的,你可以只传递缓冲区:
#include <boost/asio.hpp>
#include <boost/process.hpp>
#include <iostream>
namespace bp = boost::process;
using Args = std::vector<std::string>;
using Buffer8k = std::array<char, 8192>;
int main() {
auto first_out = std::make_unique<Buffer8k>(),
second_out = std::make_unique<Buffer8k>();
*first_out = {};
*second_out = {};
boost::asio::io_service svc;
bp::child first("/bin/echo", Args{"-n", "first"}, bp::std_out > boost::asio::buffer(*first_out), svc);
bp::child second("/bin/echo", Args{"-n", "second"}, bp::std_out >boost::asio::buffer(*second_out), svc);
std::cout << "Launched" << std::endl;
svc.run();
first.wait();
second.wait();
std::string const strFirst(first_out->data()); // uses NUL-termination (assumes text output)
std::string const strSecond(second_out->data()); // uses NUL-termination (assumes text output)
std::cout << strFirst << "\n";
std::cout << strSecond << "\n";
return first.exit_code();
}
版画
Launched
first
second
更多示例
因为我不能真正确定您需要什么,请查看我编写的其他实际展示实时异步 IO 的示例,您可能需要在其中响应一个进程的特定输出。
我已尝试将 boost::childprocess 与 async_pipe 一起使用,如下面的代码示例所示,同时期望因为有等待方法,所以对 运行 的调用不会等待被调用的可执行文件完成后再继续到我调用 wait() 的行。我的目标是多次启动同一个可执行文件,以便在 GTest 中测试实例计数方法(基于 boost 管理的共享内存段实现)。 但在此之前我需要调用 io_service::运行(),而不是等待被调用的可执行文件完成现在。有人可以告诉我我在哪里使用错了吗?或者如果这是对我的功能进行单元测试的错误方法?我一直在努力寻找解决方案! 这是我如何调用可执行文件的一个实例的示例:
int CallChildProcess_Style9() {
std::string strCmdLine = "E:\file.exe --Debug MainStartUps_Off --Lock 3";
boost::asio::io_service m_oIOS;
std::vector<char> m_oAsyncBuffer_Out;
bp::async_pipe m_oAsyncPipe_Out(m_oIOS);
std::error_code build_ec;
size_t nReadSize(0);
boost::scoped_ptr<boost::process::child> m_pChildProcess(nullptr);
m_pChildProcess.reset(new bp::child(strCmdLine.data(), bp::std_out > m_oAsyncPipe_Out, build_ec));
m_oAsyncBuffer_Out.resize(1024*8);
boost::asio::async_read(m_oAsyncPipe_Out, boost::asio::buffer(m_oAsyncBuffer_Out),
[&](const boost::system::error_code &ec, std::size_t size) { nReadSize = size; });
size_t iii = m_oIOS.run();
m_pChildProcess->wait();
m_oAsyncBuffer_Out.resize(nReadSize);
std::string strBuf(m_oAsyncBuffer_Out.begin(), m_oAsyncBuffer_Out.begin() + nReadSize);
int result = m_pChildProcess->exit_code();
m_oAsyncPipe_Out.close();
m_oIOS.reset();
return result;
}
使用io_service
要使用 async_pipe
,您需要将 io_service
实例提供给 bp::child
的参数关键字:
#include <boost/asio.hpp>
#include <boost/process.hpp>
#include <boost/process/async.hpp>
#include <boost/scoped_ptr.hpp>
#include <iostream>
namespace bp = boost::process;
int CallChildProcess_Style9() {
std::string strCmdLine = "/bin/cat";
boost::asio::io_service m_oIOS;
std::vector<char> m_oAsyncBuffer_Out;
bp::async_pipe m_oAsyncPipe_Out(m_oIOS);
std::error_code build_ec;
size_t nReadSize(0);
boost::scoped_ptr<boost::process::child> m_pChildProcess(nullptr);
std::vector<std::string> const args = { "/home/sehe/Projects/Whosebug/test.cpp" };
m_pChildProcess.reset(new bp::child(strCmdLine, args, bp::std_out > m_oAsyncPipe_Out, build_ec, m_oIOS));
std::cout << "Launched: " << build_ec.message() << std::endl;
m_oAsyncBuffer_Out.resize(1024 * 8);
boost::asio::async_read(m_oAsyncPipe_Out, boost::asio::buffer(m_oAsyncBuffer_Out),
[&](const boost::system::error_code &ec, std::size_t size) {
std::cout << "read completion handler: size = " << size << " (" << ec.message() << ")" << std::endl;
nReadSize = size;
});
std::cout << "read started" << std::endl;
size_t iii = m_oIOS.run();
std::cout << "io_service stopped" << std::endl;
std::cout << "initiate child::wait" << std::endl;
m_pChildProcess->wait();
std::cout << "wait completed" << std::endl;
std::string const strBuf(m_oAsyncBuffer_Out.data(), nReadSize);
int result = m_pChildProcess->exit_code();
m_oAsyncPipe_Out.close();
m_oIOS.reset();
return result;
}
int main() {
CallChildProcess_Style9();
}
版画
http://coliru.stacked-crooked.com/a/8a9bc6bed3dd5e0a
Launched: Success
read started
read completion handler: size = 1589 (End of file)
io_service stopped
initiate child::wait
wait completed
挂断 Child
即使已修复,async_pipe::async_read
也只会读取直到缓冲区已满或达到 EOF。如果 child 进程输出超过缓冲区大小(在您的示例中为 8k),那么它将卡住并且永远不会完成。
例如:像这样替换命令:
std::string strCmdLine = "/usr/bin/yes";
结果
生活在 Coliru
Launched: Success
read started
read completion handler: size = 8192 (Success)
io_service stopped
initiate child::wait
它将挂到无穷大。这是 而不是 因为 yes
有无限输出。任何具有大输出的命令都会挂起(例如 /bin/cat /etc/dictionaries-common/words
以相同的方式挂起)。您可以通过查看 strace 输出来证明这一点:
$ sudo strace -p $(pgrep yes)
strace: Process 21056 attached
write(1, "/home/sehe/Projects/stackoverflo"..., 8170
"fix"最简单的方法是在填满输出缓冲区后关闭输出接收器:
boost::asio::async_read(m_oAsyncPipe_Out, boost::asio::buffer(m_oAsyncBuffer_Out),
[&](const boost::system::error_code &ec, std::size_t size) {
std::cout << "read completion handler: size = " << size << " (" << ec.message() << ")" << std::endl;
nReadSize = size;
m_oAsyncPipe_Out.close();
});
这要求您在调用 wait()
之前预计 child 已退出,因此 wait()
可能会失败:
Launched: Success
read started
read completion handler: size = 8192 (Success)
io_service stopped
initiate child::wait
wait completed (Success)
退一步:您需要什么?
不过,看起来您可能把问题复杂化了。如果您乐于将输出限制为 8k,并且您所需要的只是拥有多个副本,那么为什么还要使用 async io?
任何child
已经是异步的,你可以只传递缓冲区:
#include <boost/asio.hpp>
#include <boost/process.hpp>
#include <iostream>
namespace bp = boost::process;
using Args = std::vector<std::string>;
using Buffer8k = std::array<char, 8192>;
int main() {
auto first_out = std::make_unique<Buffer8k>(),
second_out = std::make_unique<Buffer8k>();
*first_out = {};
*second_out = {};
boost::asio::io_service svc;
bp::child first("/bin/echo", Args{"-n", "first"}, bp::std_out > boost::asio::buffer(*first_out), svc);
bp::child second("/bin/echo", Args{"-n", "second"}, bp::std_out >boost::asio::buffer(*second_out), svc);
std::cout << "Launched" << std::endl;
svc.run();
first.wait();
second.wait();
std::string const strFirst(first_out->data()); // uses NUL-termination (assumes text output)
std::string const strSecond(second_out->data()); // uses NUL-termination (assumes text output)
std::cout << strFirst << "\n";
std::cout << strSecond << "\n";
return first.exit_code();
}
版画
Launched
first
second
更多示例
因为我不能真正确定您需要什么,请查看我编写的其他实际展示实时异步 IO 的示例,您可能需要在其中响应一个进程的特定输出。