根据Boost 文档(“为什么管道不关闭?”部分),以下代码将导致死锁:
#include <boost/process.hpp>
#include <iostream>
namespace bp = ::boost::process;
int main(void)
{
bp::ipstream is;
bp::child c("ls", bp::std_out > is);
std::string line;
while (std::getline(is, line))
{
std::cout << line << "\n";
}
return 0;
}
文档说:
这也会死锁,因为子进程退出时管道不会关闭。因此,即使进程结束,ipstream 仍会查找数据。
但是,我无法重现死锁(在 Linux 下)。此外,我不明白为什么会首先发生死锁。一旦子进程退出,它就会关闭管道的写端。管道的读取端仍然可供父进程读取,并且std::getline()
一旦管道缓冲区中没有更多数据可用并且写入端关闭,它就会失败,对吗?如果在子进程执行期间管道缓冲区填满,子进程将阻塞等待父进程从管道中读取足够的数据,以便它可以继续。
那么万一上面的代码会死锁,有没有简单的方法可以重现死锁场景呢?
更新:
事实上,下面这段代码使用 Boost 进程死锁:
#include <boost/process.hpp>
#include <iostream>
namespace bp = ::boost::process;
int main()
{
bp::ipstream is;
bp::child c("/bin/bash", bp::args({"-c", "ls >&40"}), bp::posix::fd.bind(40, is.rdbuf()->pipe().native_sink()));
std::string line;
while (std::getline(is, line))
{
std::cout << line << "\n";
}
c.wait();
return 0;
}
我想知道这是否真的是 Linux 下进程生成的一些不可避免的属性。使用Facebook 的Folly库中的Subprocess复制上述示例至少不会死锁:
#include <folly/Subprocess.h>
#include <iostream>
int main()
{
std::vector<std::string> arguments = {"/bin/bash", "-c", "ls >&40"};
folly::Subprocess::Options options;
options.fd(40, STDOUT_FILENO);
folly::Subprocess p(arguments, options);
std::cout << p.communicate().first;
p.wait();
return 0;
}