为什么 _popen 在这里起作用,而 boost::process 不起作用?

Why does _popen work here, but boost::process does not?

我在 windows、

上使用 _popen 有以下工作代码
m_pGNUPlot = _popen("/gnuplot/bin/gnuplot.exe", "w");
fprintf(m_pGNUPlot, "set term win\n");
fprintf(m_pGNUPlot, "set term pngcairo\n"); 
fprintf(m_pGNUPlot, "plot \"\Data.txt\" using 1:2 notitle\n"); 
fprintf(m_pGNUPlot, "set output \"\Out.png\"\n");
fprintf(m_pGNUPlot, "replot\n");
fflush(m_pGNUPlot);

但问题是cmd window 一直弹出,没有办法阻止(Link) 因此,我在 boost::process

中编写了等效代码
bp::pipe m_Write;
bp::environment env = boost::this_process::environment();
m_Plot = new bp::child("/gnuplot/bin/gnuplot.exe", bp::std_in < m_Write, env, boost::process::windows::hide);
m_Write.write("set term win\n", sizeof(char)*14);
m_Write.write("set term pngcairo\n", sizeof(char) * 19);    
m_Write("plot \"\Data.txt\" using 1:2 notitle\n", sizeof(char)*35);
m_Write("set output \"\Out.png\"\n", sizeof(char)*22);
m_Write.write("replot\n", sizeof(char) * 8);

所以,我的问题是 - 这两个代码片段是否等效?如果是这样,为什么第二个不起作用?

我没有windows,所以我在我的linux盒子上测试了一下,稍微简化一下:

#include <boost/process.hpp>
#include <iostream>

namespace bp = boost::process;

int main() {
    bp::opstream m_Write;
    boost::filesystem::path program("/usr/bin/gnuplot");
    bp::child m_Plot(program, bp::std_in = m_Write);

    m_Write << "set term png\n";
    m_Write << "set output \"Out.png\"\n";
    m_Write << "plot \"Data.txt\" using 1:2 notitle\n";
    m_Write.flush();
    m_Write.pipe().close();

    m_Plot.wait();
    std::cout << "Done, exit code: " << m_Plot.exit_code() << "\n";
}

打印:

Done, exit code: 0

并从 simplistic data 创建了这张漂亮的图片:

Windows

在 windows 上,利用 Boost Filesystem path 的强大功能来完成路径:

boost::filesystem::path program("C:\gnuplot\bin\gnuplot.exe");

其他注意事项

如果整个脚本确实是固定的,请考虑使用原始文字:

m_Write << R"(set term png
    set output "Out.png"
    plot "Data.txt" using 1:2 notitle)" << std::flush;
m_Write.pipe().close();

好的,谢谢sehe! Boost 功能强大,但缺乏教程和示例使其难以上手。

是的,所以我的最终工作代码 -

bp::opstream m_Write; //output stream to pipe   
boost::filesystem::path program("/gnuplot/bin/gnuplot.exe");
m_Plot = new bp::child(program, bp::std_in = m_Write, bp::windows::hide); //this solves the problem with _popen
m_Write << "set term png\n";
m_Write << "set term pngcairo\n"; 
m_Write << "set output \"" + ToPosixPath(sPath) + "\"\n"; //Notice how this works with std::string :)
m_Write << "plot  \"" + CreateTemp(X, Y) + "\" using 1:2 notitle\n";
m_Write << "exit\n";
m_Write.flush();
m_Write.pipe().close();

m_Plot->wait(); //boost doc states "The call to wait is necessary, to obtain it and tell the operating system, that no one is waiting for the process anymore."
delete m_Plot;

一些要点-

  • 在 windows 中支持 gnuplot.exe 本身管道的 exe,而在 linux 中有两个 - gnuplot.exe 和 pgnuplot.exe.

  • 一定要在 GUI 中测试您的脚本,此代码会自动失败! Return 代码将为 0。