如何从 C++ 中的 long-运行 子进程获取输出
How to get output from a long-running child process in C++
从 C++ 程序,我想要:
- 启动子进程。
- 等到它发出一行输出。
- 捕获那行输出,并允许子进程继续 运行ning。
这感觉应该是微不足道的,但我现在已经尝试了两种方法,并且每次都遇到了类似的障碍。首先我使用 boost::process
,像这样:
auto exe = boost::process::search_path("other_executable");
boost::process::ipstream output;
master_process_ = boost::process::child(exe, boost::process::std_out > output);
std::string important_line;
std::getline(output, important_line);
第二种方法是只使用 popen
:
FILE* master_process_ = popen("other_executable", "r");
char stdout_buffer[128];
while (fgets(stdout_buffer, sizeof(stdout_buffer), master_process_)) {
// log print here
}
在这两种情况下,程序在尝试从管道读取时都会阻塞——分别在 getline
和 fgets
中,gdb 显示它卡在低级读取函数中:
#0 0x00007ffff7dcc332 in __libc_read (fd=3, buf=0x555555581d40, nbytes=895) at ../sysdeps/unix/sysv/linux/read.c:26
#1 0x00007ffff794052c in read (__nbytes=<optimized out>, __buf=<optimized out>, __fd=<optimized out>) at /usr/include/x86_64-linux-gnu/bits/unistd.h:44
#2 boost::process::detail::posix::basic_pipe<char, std::char_traits<char> >::read (count=<optimized out>, data=<optimized out>, this=0x7fffffffcbd0)
at /usr/include/boost/process/detail/posix/basic_pipe.hpp:93
#3 boost::process::basic_pipebuf<char, std::char_traits<char> >::underflow (this=0x7fffffffcb90) at /usr/include/boost/process/pipe.hpp:202
#4 0x00007ffff7c2351a in std::basic_istream<char, std::char_traits<char> >& std::getline<char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, char) () from /lib/x86_64-linux-gnu/libstdc++.so.6
对于进一步的上下文,other_executable
是一个小的 Python 程序,当 运行 独立运行时它会按预期运行(发出输出,坚持)。它还打开了一个服务器,在这两种情况下我都可以很好地与它通信,所以它肯定会得到 运行(GDB 的分离消息进一步证实了这一点,ps
)也是如此。
我做错了什么?
事实证明这两种实现都工作正常——问题是 Python 脚本没有刷新标准输出。我以为我在这里很清楚,因为我发出了一个 \n
并且从终端调用时似乎没问题,但显然不是。
感谢您的指点,@paul-sanders。
从 C++ 程序,我想要:
- 启动子进程。
- 等到它发出一行输出。
- 捕获那行输出,并允许子进程继续 运行ning。
这感觉应该是微不足道的,但我现在已经尝试了两种方法,并且每次都遇到了类似的障碍。首先我使用 boost::process
,像这样:
auto exe = boost::process::search_path("other_executable");
boost::process::ipstream output;
master_process_ = boost::process::child(exe, boost::process::std_out > output);
std::string important_line;
std::getline(output, important_line);
第二种方法是只使用 popen
:
FILE* master_process_ = popen("other_executable", "r");
char stdout_buffer[128];
while (fgets(stdout_buffer, sizeof(stdout_buffer), master_process_)) {
// log print here
}
在这两种情况下,程序在尝试从管道读取时都会阻塞——分别在 getline
和 fgets
中,gdb 显示它卡在低级读取函数中:
#0 0x00007ffff7dcc332 in __libc_read (fd=3, buf=0x555555581d40, nbytes=895) at ../sysdeps/unix/sysv/linux/read.c:26
#1 0x00007ffff794052c in read (__nbytes=<optimized out>, __buf=<optimized out>, __fd=<optimized out>) at /usr/include/x86_64-linux-gnu/bits/unistd.h:44
#2 boost::process::detail::posix::basic_pipe<char, std::char_traits<char> >::read (count=<optimized out>, data=<optimized out>, this=0x7fffffffcbd0)
at /usr/include/boost/process/detail/posix/basic_pipe.hpp:93
#3 boost::process::basic_pipebuf<char, std::char_traits<char> >::underflow (this=0x7fffffffcb90) at /usr/include/boost/process/pipe.hpp:202
#4 0x00007ffff7c2351a in std::basic_istream<char, std::char_traits<char> >& std::getline<char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, char) () from /lib/x86_64-linux-gnu/libstdc++.so.6
对于进一步的上下文,other_executable
是一个小的 Python 程序,当 运行 独立运行时它会按预期运行(发出输出,坚持)。它还打开了一个服务器,在这两种情况下我都可以很好地与它通信,所以它肯定会得到 运行(GDB 的分离消息进一步证实了这一点,ps
)也是如此。
我做错了什么?
事实证明这两种实现都工作正常——问题是 Python 脚本没有刷新标准输出。我以为我在这里很清楚,因为我发出了一个 \n
并且从终端调用时似乎没问题,但显然不是。
感谢您的指点,@paul-sanders。