【C++并发】[goes_popen] C++执行不会自动结束的shell指令,如何管理这些子进程?

4 篇文章 0 订阅
3 篇文章 0 订阅

问题描述

另一篇博客相同:

比如ros2 topic pub就是一个可能不会自动结束的shell指令,在C++进行并发设计时,往往可能导致这些进程变成野进程

因此我们需要主动管理 / 退出他们

我实现了一个goes_popen()接口,用于更加简洁地管理这类问题。

接口效果

  • 提供非阻塞的终端指令反馈方法。(不同于python的subprocess库的checkout()接口)
  • 提供主动退出/关闭指令的接口。 (真正意义的terminate())
  • 同时支持终端反馈存入变量 和 终端打印。

使用demo

#include "new_popen.hpp"


std::string command = R"(
ros2 topic pub /initialpose geometry_msgs/PoseWithCovarianceStamped "\
header:
    stamp:
        sec: 0,
        nanosec: 0
    frame_id: 'map'
pose:
    pose:
        position: 
            x: -2.0,
            y: -0.5,
            z: 0.0
        orientation:
            x: 0.0, 
            y: 0.0, 
            z: 0.01, 
            w: 1.0
    covariance: [0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.06853891909122467]
" -1 
)";
std::string command_1 = "ros2 topic echo /scan --full-length --once";
std::string command_2 = "ros2 topic list";


inline void a_gap(){
    // it's just a gap
    for (int i = 0; i < 3; ++i) {
        std::cout << "Main thread is doing task " << i << std::endl;
        // 在这里添加其他任务代码
        std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟执行任务的耗时
    }
}
int main() {
    // Introduction to API:

    // 1. create a commander:
    // 执行命令
    CommandProcess::SharedPtr proc_1 = goes_popen(
        command,false,false
    );
    CommandProcess::SharedPtr proc_2 = goes_popen(
        command_1,false,true
    );                // drop the stderr
    CommandProcess::SharedPtr proc_3 = goes_popen(
        command_2,true,false
    );           // drop the stdout
    
    a_gap();

    // 2. terminate commander
    proc_1->terminate();

    // 3. block the main-proc
    proc_1->join();

    // 4. positive check if_finished()
    if(proc_1->if_finished()) std::cout << "proc_1 has terminate" << std::endl;
    if(proc_2->if_finished()) std::cout << "proc_2 has terminate" << std::endl;
    else std::cout << "proc_2 is still working" << std::endl;
    // 5. get the output from the command
    std::string result = proc_3->get_output(); // it will block the main-proc, until command finished
    std::cout << "read from proc_3: \n" << result << std::endl;

    // 6. how to get the result with no block?
    // OR how to terminate during the result reading?
    //    use structure like following:
        // Firstly, you should provide 3 states:
            bool exit_flag_ = false;
            std::string result_2 = "";
            std::thread t; 
        // Secondly, get_output_noblock
        get_output_noblock(
            &t,          // you should provide a thread
            exit_flag_, // the shutdown flag you could control
            proc_2,     // CommandProcess you need to get_ouput_noblock
            result_2    // the result would be written into it.
        );
        // Thirdly, early shutdown module
            // you should read result after ->if_finished() is true
        while(!proc_2->if_finished()){
            a_gap();
                // change exit_flag_ = true when you need to pre-shutdown proc_1
                {
                  //  exit_flag_=true; // it will cancel your command
                }
            if(exit_flag_==true) break;
        }
        // [important!]: before read result
        proc_2->join();
        t.join();
        std::cout << "read from proc_2: " << result_2 << std::endl;
    // [notice]: you can only get the output after finished
    // if you early shutdown the command, you would read nothing.

    proc_1.reset();
    proc_2.reset();
    proc_3.reset();

    return 0;
}




实现原理概述

  1. 一个指令两次fork进程。一个子进程用于管道通信,获取终端指令的反馈;另一个子进程用于执行exec()进行进程变身,执行shell指令。
  2. 管道通信。 将终端反馈重定向到两个子进程的管道中,从而实现终端反馈的获取。
  3. 共享内存。将终端反馈存入共享内存,从而实现更方便的读取操作。

仓库链接

https://github.com/GoesM/goes_popen

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GoesM

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值