boost:进程管理

概述

Boost.Process提供了一个灵活的C++ 进程管理框架。它允许C++ developer可以像Java和.Net程序developer那样管理进程。它还提供了管理当前执行进程上下文、创建子进程、用C++ 流和异步I/O进行通信的能力。
该库以完全透明的方式将所有进程管理的抽象细节呈现给使用者,且该库是跨平台的。

特点

进程管理

Boost.Process的长期目标是提供一个抽象于操作系统之上的,可以管理任何运行的进程的框架。由于提供这样的API比较困难,所以现在只专注于管理。Boost.Process的最重要的特征就是启动一个外部应用、控制它们并与它们交互。传统上讲,对于C和C++ 来说,就比较困难了,因为它们要启动新进程、执行外部程序、建立匿名管道来交互、等待进程结束、检查进程退出码等。更糟糕的是不同操作系统,相关的进程模块和API是不同的。所以,Boost.Process的出现就提供了便利条件。

输入输出重定向

一般来说一个应用启动了子进程,它们可能会通过传输数据来交流。这种进程间通信是文件句柄层面的,通常涉及stdin、stdout、stderr。如果操作系统支持,那么就需要可重定向的流。不过这对C++ 来说是很容易的。

不同操作模式

支持同步、异步、分离

管道管理

这样就可以实现一个进程的输出可以作为另一个进程的输入。

库的设计图

最重要的类就是Context和Process。Context提供了进程运行的上下文。pistream和postream是为了交互。父进程还可以等待子进程退出,并检查进程退出码。如果有例如包含管道的shell命令要执行,那么pipeline_entry就应运而生了,它可以实现前一个子进程的输出是下一个子进程的输入。

使用步骤

1、创建上下文Context
2、创建子进程,获得子进程对象
3、如果有重定向,可以访问到stdin、stdout、stderr
4、进程结束,检查进程退出码

教程

一个最简单的例子

#include <boost/filesystem.hpp>

#include <boost/process.hpp>

#include <string>

#include <vector>

namespace bp = ::boost::process;

bp::child start_child()

{

    std::string exec = "bjam";

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

    args.push_back("bjam");

    args.push_back("--version");

    bp::context ctx;

    ctx.stdout_behavior = bp::capture_stream();

    return bp::launch(exec, args, ctx);

}

int main()

{

    bp::child c = start_child();

    bp::pistream &is = c.get_stdout();

    std::string line;

    while (std::getline(is, line))

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

    bp::status s = c.wait();

    return s.exited() ? s.exit_status() : EXIT_FAILURE;

}

下面再看一个异步的例子

#include <boost/filesystem.hpp>

#include <boost/asio.hpp>

#include <boost/process.hpp>

#include <boost/array.hpp>

#include <boost/bind.hpp>

#include <string>

#include <vector>

#include <iostream>

namespace bp = ::boost::process;

namespace ba = ::boost::asio;

ba::io_service io_service;

boost::array<char, 4096> buffer;

ba::posix::stream_descriptor in(io_service);

bp::child start_child()

{

    std::string exec = "bjam";

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

    args.push_back("bjam");

    args.push_back("--version");

    bp::context ctx;

    ctx.stdout_behavior = bp::capture_stream();

    ctx.environment = bp::self::get_environment();

    return bp::launch(exec, args, ctx);

}

void end_read(const boost::system::error_code &ec, std::size_t bytes_transferred);

void begin_read()

{

    in.async_read_some(boost::asio::buffer(buffer),

        boost::bind(&end_read, ba::placeholders::error, ba::placeholders::bytes_transferred));

}

void end_read(const boost::system::error_code &ec, std::size_t bytes_transferred)

{

    if (!ec)

    {

        std::cout << std::string(buffer.data(), bytes_transferred) << std::flush;

        begin_read();

    }

}

int main()

{

    bp::child c = start_child();

    bp::pistream &is = c.get_stdout();

    in.assign(is.handle().release());

    begin_read();

    io_service.run();

    c.wait();

}

这个例子中用到了asio库,涉及到许多回调函数。关于异步(asio)暂时不做讲解,写这个例子是为了展示该库的异步功能。对异步感兴趣的同学可以看一下《Boost.Asio C++ Network Programming

部分文件和类

stream_behaviour.hpp文件

对于流的描述,可分为六种类型

序号 流描述 含义
1 capture  父子进程之间通过无名管道相互接收数据 
2 close  启动时关闭 
3 inherit  父子进程共用一个,也即继承 
4 redirect_to_stdout  主要用在stderr时,重定向到stdout 
5 silence  输出重定向到/dev/null 
6 posix_redirect  将输出重定向到指定的文件描符,是对redirect_to_stdout的扩展 

以下是等价的
boost::process::child::get_stdin() <==> boost::process::posix_child::get_input(STDIN_FILENO)
boost::process::child::get_stdout() <==> boost::process::posix_child::get_output(STDOUT_FILENO)
boost::process::child::get_stderr() <==> boost::process::posix_child::get_output(STDERR_FILENO)

重定向的例子

#include <boost/process.hpp>

#include <boost/filesystem.hpp>

#include <string>

#include <vector>

#include <iostream>

#include <cstdlib>

#include <unistd.h>

namespace bp = ::boost::process;

bp::posix_child start_child()

{

    std::string exec = bp::find_executable_in_path("dbus-daemon");

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

    args.push_back("dbus-daemon");

    args.push_back("--fork");

    args.push_back("--session");

    args.push_back("--print-address=3");

    args.push_back("--print-pid=4");

    bp::posix_context ctx;

    ctx.output_behavior.insert(bp::behavior_map::value_type(STDOUT_FILENO, bp::inherit_stream()));

    ctx.output_behavior.insert(bp::behavior_map::value_type(STDERR_FILENO, bp::inherit_stream()));

    ctx.output_behavior.insert(bp::behavior_map::value_type(3, bp::capture_stream()));

    ctx.output_behavior.insert(bp::behavior_map::value_type(4, bp::capture_stream()));

    return bp::posix_launch(exec, args, ctx);

}

int main()

{

    try

    {

        bp::posix_child c = start_child();

        std::string address;

        pid_t pid;

        c.get_output(3) >> address;

        c.get_output(4) >> pid;

        bp::status s = c.wait();

        if (s.exited())

        {

            if (s.exit_status() == EXIT_SUCCESS)

            {

                std::cout << "D-BUS daemon‘s address is: " << address << std::endl;

                std::cout << "D-BUS daemon‘s PID is: " << pid << std::endl;

            }

            else

                std::cout << "D-BUS daemon returned error condition: " << s.exit_status() << std::endl;

        }

        else

            std::cout << "D-BUS daemon terminated abnormally" << std::endl;

        return s.exited() ? s.exit_status() : EXIT_FAILURE;

    }

    catch (boost::filesystem::filesystem_error &ex)

    {

        std::cout << ex.what() << std::endl;

        return EXIT_FAILURE;

    }

}

boost::process::context类

template <class Path>

class basic_context : public basic_work_directory_context<Path>, public environment_context

{

public:

    /**

     * Child‘s stdin behavior.

     */

    stream_behavior stdin_behavior;

    /**

     * Child‘s stdout behavior.

     */

    stream_behavior stdout_behavior;

    /**

     * Child‘s stderr behavior.

     */

    stream_behavior stderr_behavior;

};

typedef basic_context<std::string> context;

而basic_work_directory_context是用来设置工作目录的;environment_context实质上是个包装了boost::process::environment的类,boost::process::environment是一个map<string, string>,用以保存环境变量。

boost::process::posix_context类

typedef std::map<int, stream_behavior> behavior_map;

template <class Path>

class posix_basic_context : public basic_work_directory_context<Path>, public environment_context

{

public:

    /**

     * Constructs a new POSIX-specific context.

     *

     * Constructs a new context. It is configured as follows:

     * * All communcation channels with the child process are closed.

     * * There are no channel mergings.

     * * The initial work directory of the child processes is set to the

     *   current working directory.

     * * The environment variables table is empty.

     * * The credentials are the same as those of the current process.

     */

    posix_basic_context()

        : uid(::getuid()),

        euid(::geteuid()),

        gid(::getgid()),

        egid(::getegid())

    {

    }

    /**

     * List of input streams that will be redirected.

     */

    behavior_map input_behavior;

    /**

     * List of output streams that will be redirected.

     */

    behavior_map output_behavior;

    /**

     * The user credentials.

     *

     * UID that specifies the user credentials to use to run the %child

     * process. Defaults to the current UID.

     */

    uid_t uid;

    /**

     * The effective user credentials.

     *

     * EUID that specifies the effective user credentials to use to run

     * the %child process. Defaults to the current EUID.

     */

    uid_t euid;

    /**

     * The group credentials.

     *

     * GID that specifies the group credentials to use to run the %child

     * process. Defaults to the current GID.

     */

    gid_t gid;

    /**

     * The effective group credentials.

     *

     * EGID that specifies the effective group credentials to use to run

     * the %child process. Defaults to the current EGID.

     */

    gid_t egid;

    /**

     * The chroot directory, if any.

     *

     * Specifies the directory in which the %child process is chrooted

     * before execution. Empty if this feature is not desired.

     */

    Path chroot;

};

/**

 * Default instantiation of posix_basic_context.

 */

typedef posix_basic_context<std::string> posix_context;

函数boost::process::self::get_environment()可以得到当前进程的环境变量。
我们可以对环境变量进行修改,如
boost::process::environment_context env;
env.insert(boost::process::environment::valuetype(“A”, “a”));

进程结束码类信息

class status

{

    friend class child;

public:

    /**

     * 进程是否正常退出

     */

    bool exited() const;

    /**

     * 进程返回值

     */

    int exit_status() const;

protected:

    status(int flags);

    ...

};

class posix_status : public status

{

public:

    posix_status(const status &s);

    /**

     * 进程是否因为信号终止

     */

    bool signaled() const;

    /**

     * 如果因为信号终止,那么是因为哪个信号终止的

     */

    int term_signal() const;

    /**

     * 是否core dump了

     */

    bool dumped_core() const;

    /**

     * 进程是否因为收到信号停止

     */

    bool stopped() const;

    /**

     * 如果进程因为收到信号停止,那么信号是哪个

     */

    int stop_signal() const;

}

进程类对象信息

class process

{

public:

    typedef pid_t id_type;

    process(id_type id);

    /**

     * Returns the process‘ identifier.

     */

    id_type get_id() const;

    /**

     * 强制终止一个进程,force为真则用SIGKILL杀死,否则用SIGTERM杀死

     */

    void terminate(bool force = false) const ;

private:

    ...

};

class child : public process

{

public:

    /**

     * 获得标准输出

     */

    postream &get_stdin() const;

    /**

     * 获得标准输入

     */

    pistream &get_stdout() const;

    /**

     * 获得标准错误输入

     */

    pistream &get_stderr() const;

    /**

     * 阻塞等待进程退出,返回状态码对象

     */

    status wait();

    /**

     * 创建一个子进程对象

     */

    child(id_type id, detail::file_handle fhstdin, detail::file_handle fhstdout, detail::file_handle fhstderr, detail::file_handle fhprocess = detail::file_handle());

private:

    ...

};

class posix_child : public child

{

public:

    /**

     * 从指定描述符获得一个输出流

     */

    postream &get_input(int desc) const;

    /**

     * 从指定描述符获得一个输入流

     */

    pistream &get_output(int desc) const;

    /**

     *构造函数

     */

    posix_child(id_type id, detail::info_map &infoin, detail::info_map &infoout);

private:

    ...

};

children类

children类实际上std::vector<child>。children的启动方式是一个输出流被链接到下一个子进程的输入流上。

#include <boost/process.hpp>

#include <string>

#include <vector>

#include <iostream>

#include <fstream>

#include <cstdlib>

namespace bp = ::boost::process;

bp::children start_children()

{

    bp::context ctxin;

    ctxin.stdin_behavior = bp::capture_stream();

    bp::context ctxout;

    ctxout.stdout_behavior = bp::inherit_stream();

    ctxout.stderr_behavior = bp::redirect_stream_to_stdout();

    std::string exec1 = bp::find_executable_in_path("cut");

    std::vector<std::string> args1;

    args1.push_back("cut");

    args1.push_back("-d ");

    args1.push_back("-f2-5");

    std::string exec2 = bp::find_executable_in_path("sed");

    std::vector<std::string> args2;

    args2.push_back("sed");

    args2.push_back("s,^,line: >>>,");

    std::string exec3 = bp::find_executable_in_path("sed");

    std::vector<std::string> args3;

    args3.push_back("sed");

    args3.push_back("s,$,<<<,");

    std::vector<bp::pipeline_entry> entries;

    entries.push_back(bp::pipeline_entry(exec1, args1, ctxin));

    entries.push_back(bp::pipeline_entry(exec2, args2, ctxout));

    entries.push_back(bp::pipeline_entry(exec3, args3, ctxout));

    return bp::launch_pipeline(entries);

}

int main(int argc, char *argv[])

{

    try

    {

        if (argc < 2)

        {

            std::cerr << "Please specify a file name" << std::endl;

            return EXIT_FAILURE;

        }

        std::ifstream file(argv[1]);

        if (!file)

        {

            std::cerr << "Cannot open file" << std::endl;

            return EXIT_FAILURE;

        }

        bp::children cs = start_children();

        bp::postream &os = cs.front().get_stdin();

        std::string line;

        while (std::getline(file, line))

            os << line << std::endl;

        os.close();

        bp::status s = bp::wait_children(cs);

        return s.exited() ? s.exit_status() : EXIT_FAILURE;

    }

    catch (boost::filesystem::filesystem_error &ex)

    {

        std::cout << ex.what() << std::endl;

        return EXIT_FAILURE;

    }

}

需要注意的是,wait_children出错时,返回第一个子进程的退出码,所有子进程都正常退出时,返回最后一个子进程的退出码。

master3中大量用到进程管理这个库。这个Boost.Process库可以在这里获得点这里

时间: 2024-10-22 13:02:03

boost:进程管理的相关文章

linux进程管理

进程管理 进程 Process 某应用程序打开的进程 PID Process ID 类型: 用户空间进程 内核空间进程 静态查看进程的状态 # ps [[email protected] ~]# ps >>>>查看本终端的进程 PID TTY          TIME CMD 4206 pts/0    00:00:00 bash 4378 pts/0    00:00:00 ps 选项的使用方式: BSD风格:选项没有横线- ps aux SysV风格:选项需要带有横线-  

Linux进程管理与调度-之-目录导航【转】

转自:http://blog.csdn.net/gatieme/article/details/51456569 版权声明:本文为博主原创文章 && 转载请著名出处 @ http://blog.csdn.net/gatieme 目录(?)[-] 项目链接 进程的描述 进程的创建 进程的加载与运行 进程的退出 进程的调度 调度普通进程-完全公平调度器CFS 日期 内核版本 架构 作者 GitHub CSDN 2016-07-21 Linux-4.6 X86 & arm gatieme

Linux进程管理工具 Supervisord 的安装 及 入门教程

Supervisor是一个进程管理工具,官方的说法: 用途就是有一个进程需要每时每刻不断的跑,但是这个进程又有可能由于各种原因有可能中断.当进程中断的时候我希望能自动重新启动它,此时,我就需要使用到了Supervisor 主要就两个命令: supervisord : supervisor的服务器端部分,启动 supervisor 就是运行这个命令 supervisorctl:启动 supervisor 的命令行窗口. 安装(CentOS): 方式一: yum -y install python-

Linux进程管理简谈

Linux系统进程管理简谈 进程是什么? 简单来说进程是一个正在执行的程序的一个副本,存在生命周期,有段指令和代码在不断运行. linux内核存储信息的固定格式:task struct 进程的相关信息存储在链表中 多个任务的task struct组件的链表:task list 进程的创建:父进程创建子进程(内核创建init进程,剩余一切进程有init及其子进程进程创建) 父进程创建子进程时向内核调用fork()来创建子进程并且通过调用clone()复制父进程的信息给子进程 Linux进程的优先级

Linux之进程管理及Shell脚本

使用!来调用过往命令 !! 重复执行上一条指令 !a 重复执行上一条以a为首的指令 !nubmer 重复执行上一条在history表中记录号码为number的指令 !-number重复执行前第number条指令 ailas abc='cd xxxxxxxxxxx/xxxxxxxx/xxxxxxxxxxxxx' unalias abc " "将一串字符当成字符串来看,可以转译特殊字符 ' '将一串字符当成字符串来看,无法转译特殊字符 ·能够返回命令执行的结果 echo `uname -a

进程管理

一.进程 1.概念 内核的功用:进程管理.文件系统.网络功能.内存管理.驱动程序.安全功能等 Process: 运行中的程序的一个副本,是被载入内存的一个指令集合 进程ID(Process ID,PID)号码被用来标记各个进程 UID.GID.和SELinux语境决定对文件系统的存取和访问权限, 通常从执行进程的用户来继承 存在生命周期 task struct:Linux内核存储进程信息的数据结构格式 task list:多个任务的的taskstruct组成的链表 进程创建: init:第一个进

supervisor——进程管理工具

Supervisor (http://supervisord.org) 是一个用 Python 写的进程管理工具,可以很方便的用来启动.重启.关闭进程(不仅仅是 Python 进程).除了对单个进程的控制,还可以同时启动.关闭多个进程,比如很不幸的服务器出问题导致所有应用程序都被杀死,此时可以用 supervisor 同时启动所有应用程序而不是一个一个地敲命令启动. 1.安装 Supervisor 可以运行在 Linux.Mac OS X 上.如前所述,supervisor 是 Python 编

第五课 进程管理

unix_c_05.txt================第五课 进程管理================一.基本概念------------1. 进程与程序~~~~~~~~~~~~~1) 进程就是运行中的程序.一个运行着的程序,可能有多个进程.进程在操作系统中执行特定的任务.2) 程序是存储在磁盘上,包含可执行机器指令和数据的静态实体.进程或者任务是处于活动状态的计算机程序.2. 进程的分类~~~~~~~~~~~~~1) 进程一般分为交互进程.批处理进程和守护进程三类.2) 守护进程总是活跃的

进程管理、内存管理、存储管理初步了解

进程管理 进程需要一定的资源(包括CPU时间.内存.文件.I/O设备)以完成其任务.这些资源可以在进程创建时分配给进程,也可以在执行进程时分配给进程.除了在创建时得到各种物理和逻辑资源外,进程还可以接受传输过来的各种初始化数据(输入). 需要注意:程序本省并不是进程,程序是被动的实体,而进程是一个活动的实体. 进程与线程的定义: 进程是具有一定独立功能的程序关于某个数据集合上的依次运行活动,进程是系统进行资源分配和调度的独立单位. 线程是进程的一个实体,是CPU和分配的基本单位.线程自己基本不拥