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库可以在这里获得点这里。
boost:进程管理的更多相关文章
- C++ Windows进程管理
功能: 1.各个进程启动.挂起.恢复.停止等 2.监听进程的运行状态,进程退出(正常.非正常)时,通知用户 3.异步队列 4.线程安全 进程管理器类: #ifndef __ProcessManager ...
- 《Linux内核设计与实现》读书笔记 第三章 进程管理
第三章进程管理 进程是Unix操作系统抽象概念中最基本的一种.我们拥有操作系统就是为了运行用户程序,因此,进程管理就是所有操作系统的心脏所在. 3.1进程 概念: 进程:处于执行期的程序.但不仅局限于 ...
- 进程管理三大扩展工具htop
三大进程管理监控工具 HTOP 介绍: Htop是一款运行于Linux系统监控与进程管理软件,htop提供所有进程的列表,并且使用彩色标识出处理器.swap和内存状态.用户一般可以在top无法提供详尽 ...
- Linux进程管理子系统分析【转】
本文转载自:http://blog.csdn.net/coding__madman/article/details/51298732 Linux进程管理: 进程与程序: 程序:存放在磁盘上的一系列代码 ...
- Linux下取代top的进程管理工具 htop
一.htop 简介 This is htop, an interactive process viewer for Linux. It is a text-mode application (for ...
- Linux进程管理
一.进程管理简介 进程是正在执行的程序或命令,每一个进程都是一个运行实体,都有自己的地址空间,并占用一定的系统资源. 进程管理的作用: 1.判断服务器的健康状态 2.查看系统中的所有进程 3.杀死进程 ...
- 12个Linux进程管理命令介绍(转)
12个Linux进程管理命令介绍 [日期:2015-06-02] 来源:Linux中国 作者:Linux [字体:大 中 小] 执行中的程序在称作进程.当程序以可执行文件存放在存储中,并且运行的 ...
- 理解Docker容器的进程管理
摘要: Docker在进程管理上有一些特殊之处,如果不注意这些细节中的魔鬼就会带来一些隐患.另外Docker鼓励"一个容器一个进程(one process per container)&qu ...
- Android内存进程管理机制
参考文章: http://www.apkbus.com/android-104940-1-1.htmlhttp://blog.sina.com.cn/s/blog_3e3fcadd0100yjo2.h ...
随机推荐
- perl处理含有中文字符的json编码
例子:1. 有php的 json函数生成的中文串 [root@tts177:/tmp]$/opt/php/bin/php -r 'echo json_encode(Array("a" ...
- Java中的JDBC基础
简介 JAVA程序想要对数据库进行访问,需要有JDBC驱动程序的支持.JDBC驱动程序提供了对各种主流数据库的接口,程序员只需要学习掌握这一套接口,就可以实现对所有数据库的访问代码编写. 一般步骤 J ...
- CRM PrincipalObjectAccess(POA)
PrincipalObjectAccess (POA) table is an important table which holds all grants share on CRM objects. ...
- gRPC 的 RoadMap 20160325 更新
gRPC是一个高性能.通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众多开发 ...
- Codeforces 119C DP
题意: 有n天,m门课和常数k; 每天上一门课,每门课程有两个属性,最少作业量a,最多作业量b,和难度c. 1<=a<=b<=1e16 c<=100 1<=n<=m ...
- 使用jaxp对比xml进行DOM解析
/*DOM解析编程 •遍历所有节点 •查找某一个节点 •删除结点 •更新结点 •添加节点 /* package cn.itcast.jaxp; import java.io.File; import ...
- MapReduce从HBase读写数据简单示例
就用单词计数这个例子,需要统计的单词存在HBase中的word表,MapReduce执行的时候从word表读取数据,统计结束后将结果写入到HBase的stat表中. 1.在eclipse中建立一个ha ...
- JDBC建立/关闭数据库连接
JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口 ...
- 菜鸟-手把手教你把Acegi应用到实际项目中(8)-扩展UserDetailsService接口
一个能为DaoAuthenticationProvider提供存取认证库的的类,它必须要实现UserDetailsService接口: public UserDetails loadUserByUse ...
- C# UserControl 判断DesignMode
C# UserControl 判断DesignMode .Net开发UserControl时,我们经常需要得知当前是Design Mode还是Runtime Mode. 在Design Mode时 ...