C++ 启动子进程时的争用条件会导致管道读数挂起

C++ 启动子进程时的争用条件会导致管道读数挂起,c++,linux,boost,boost-process,C++,Linux,Boost,Boost Process,我有两个线程,每个线程启动一个子进程。第一个应用程序是一个运行时间相当长的二进制程序。第二个出口相当快 有一个竞争条件,有时会导致失败。下面我有一个最低可行的代码示例 它使用boostprocess0.5,它使用标准的fork/execve/dup2系统。关于Boost过程如何工作,有一些黑客攻击,但总体来说,它工作得相当好 父进程启动了更多的进程,并且通常是有效的 我不能一次启动一个进程,特别是因为我不知道哪些部分不能交错 你知道为什么会这样吗 预期产出: /etc/init.d/led re

我有两个线程,每个线程启动一个子进程。第一个应用程序是一个运行时间相当长的二进制程序。第二个出口相当快

有一个竞争条件,有时会导致失败。下面我有一个最低可行的代码示例

它使用boostprocess0.5,它使用标准的fork/execve/dup2系统。关于Boost过程如何工作,有一些黑客攻击,但总体来说,它工作得相当好

父进程启动了更多的进程,并且通常是有效的

我不能一次启动一个进程,特别是因为我不知道哪些部分不能交错

你知道为什么会这样吗

预期产出:

/etc/init.d/led restart: Creating child
Creating child1
Reading STDOUT
/etc/init.d/led restart: Waiting for it to exit
Reading std_err_pipe


wait_for_exit(pullapp);
Reading std_out_pipe
< file list>

Done
/etc/init.d/led重启:创建子节点
创建孩子1
阅读标准
/etc/init.d/led重启:等待退出
读取标准错误管道
等待退出(pullapp);
读取标准管道
<文件列表>
多恩
然而,它常常(但并非总是)在标准错误管道处停止

#include <iostream>
#include <string>
#include <vector>

#include <boost/iostreams/stream.hpp>
#include <boost/process.hpp>
#include <boost/thread.hpp>

void run_sleep()
{
    int      exit_code;
    std::string   str;

    std::vector< std::string >  args;

    boost::shared_ptr<boost::process::child> child;

    args.push_back(boost::process::search_path("sleep"));
    args.push_back("20");

    boost::iostreams::stream< boost::iostreams::file_descriptor_source >
        out_stream;

    boost::process::pipe out_pipe = boost::process::create_pipe();

    {
        //MUST BE IN SEPARATE SCOPE SO SINK AND SOURCE ARE DESTROYED
        // See http://stackoverflow.com/a/12469478/5151127
        boost::iostreams::file_descriptor_sink    out_sink
            (out_pipe.sink,   boost::iostreams::close_handle);
        boost::iostreams::file_descriptor_source  out_source
            (out_pipe.source, boost::iostreams::close_handle);

        std::cout << "Creating child1" << std::endl;
        child.reset(new boost::process::child(
            boost::process::execute(
                boost::process::initializers::run_exe(args[0]),
                boost::process::initializers::set_args(args),
                boost::process::initializers::bind_stdout(out_sink),
                boost::process::initializers::bind_stderr(out_sink)
            )
        ));

        out_stream.open(out_source);
    }

    std::cout << "Reading STDOUT" << std::endl;
    while( out_stream ) {
        std::string line;

        std::getline(out_stream, line);

        std::cout << line << std::endl;
    }

    std::cout << "wait_for_exit(pullapp);" << std::endl;
    exit_code = wait_for_exit(*child);

    child.reset();

    return;
}


void run_ls()
{
    int      exit_code;
    std::string   str;

    std::vector< std::string >  args ;

    args.push_back(boost::process::search_path("ls"));
    args.push_back("/lib");

    boost::process::pipe std_out_pipe = boost::process::create_pipe();
    boost::process::pipe std_err_pipe = boost::process::create_pipe();

    std::cout << "/etc/init.d/led restart: Creating child" << std::endl;

    {
        boost::process::child child = boost::process::execute(
            boost::process::initializers::set_args(args),
            boost::process::initializers::bind_stdout(
                boost::iostreams::file_descriptor_sink(
                    std_out_pipe.sink,
                    boost::iostreams::close_handle
                )
            ),
            boost::process::initializers::bind_stderr(
                boost::iostreams::file_descriptor_sink(
                    std_err_pipe.sink,
                    boost::iostreams::close_handle
                )
            ),
            boost::process::initializers::throw_on_error()
        );

        std::cout << "/etc/init.d/led restart: Waiting for it to exit" << std::endl;
        exit_code = wait_for_exit(child);
    }

    { //with std_err_stream, istream
        boost::iostreams::stream< boost::iostreams::file_descriptor_source >
            std_err_stream(
                boost::iostreams::file_descriptor_source(
                    std_err_pipe.source, boost::iostreams::close_handle
                )
            );

        std::cout << "Reading std_err_pipe" << std::endl;
        std::istream istream(std_err_stream.rdbuf());
        while( istream ) {
            getline(istream, str);
            std::cout << str << std::endl;
        }
    }

    { //with std_out_stream, istream
        boost::iostreams::stream< boost::iostreams::file_descriptor_source >
            std_out_stream(
                boost::iostreams::file_descriptor_source(
                    std_out_pipe.source, boost::iostreams::close_handle
                )
            );

        std::cout << "Reading std_out_pipe" << std::endl;
        std::istream istream(std_out_stream.rdbuf());
        while( istream ) {
            getline(istream, str);
            std::cout << str << std::endl;
        }
    }

    std::cout << "Done" << std::endl;
}

int main()
{
    boost::thread  run_sleep_tr(run_sleep);
    boost::thread  run_ls_tr(run_ls);

    run_sleep_tr.join();
    run_ls_tr.join();

    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
void run_sleep()
{
int-exit_码;
std::字符串str;
std::vectorargs;
boost::共享的ptr子级;
args.push_back(boost::process::search_path(“sleep”);
args.推回(“20”);
boost::iostreams::stream
外流;
boost::process::pipe out_pipe=boost::process::create_pipe();
{
//必须在单独的作用域中,以便销毁接收器和源
//看http://stackoverflow.com/a/12469478/5151127
boost::iostreams::文件\描述符\接收器输出\接收器
(out_pipe.sink,boost::iostreams::close_handle);
boost::iostreams::文件\描述符\源输出\源
(out_pipe.source,boost::iostreams::close_handle);

显然,这是因为文件句柄在多个进程中结束。这些进程不会关闭这些句柄,因此父进程仍在等待

对于Linux,修复相对容易;管道应该在
create\u pipe
中使用
O\u CLOEXEC
创建。方法
bind.*
中的
dup2
调用清除此标志,这足以使管道正常工作

在Windows上,我还没有找到真正的解决方案。您必须将句柄标记为可继承。可以在
executor()
方法中执行此操作,但这可能需要一个全局互斥。我还没有时间仔细研究它。

我不确定是否“使用boost.process 0.6”这算是一个答案,但这对你来说就足够了。在一些错误报告之后,这就是答案。
在windows上,关闭父进程中的接收器就足够了。

显然,我使用的Boost进程是旧版本。最新版本是。