boost::process移植笔记

本文详细记录了Boost::Process库的移植过程,重点讨论了元函数、child类的构造、executor类的设计以及在Windows下的实现细节。通过样例代码展示了如何在VC2010中编译和使用该库,并提出了对boost::fusion算法和管道设计的一些疑问。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


最近想做一个进程管理器,因为这段时间在学boost,所以就选择了boost::process,但一用才发现,VC2010下编译报错了。
原因是process中用到了不少C++11的语法,2010支持不完整。
所以,就有了这次的移植笔记。
不用告诉我VC2019可以完美支持,本人就是觉得VC2010够清新简洁,不会启动那么多乱七八糟的进程,浪费资源,哈哈哈。
其实重复造轮子才能真正学到别人代码的设计理念嘛,估计这个才算是瞎折腾的真正动力。
移植后的代码丢到github上了,地址在最后可以找到。

process移植笔记

元函数

元函数是在boost::mpl的文档中看到的,感觉挺有意思,而且也被process大量使用,因此,有必要先做个铺垫,这样后面的内容才好展开。

在理解元函数之前,先看看C++中的一个常规函数长啥样,两者结合,可能会更容易理解元函数的概念。

常规函数的基本要素

int MyFunc(int fld1)
{
    //根据实际需要,干点有意义的事情

    return 111;
}

上面定义了一个函数,名字为MyFunc,其包含3个重要部分:

  • 入参
  • 函数体
  • 返回结果

MyFunc的作用是:将输入的入参fld1,经过一定的处理后,得到我们想要的结果111。

元函数使用场景举例

为了对元函数有个初步印象,我们先来看一个实际的使用场景。

试想有个通讯模块,负责将本机的数据发给远程主机,这时,我们要考虑以下这些问题:

  • 对于整数类型,不同机器的字节序不一样,有的是小端,有的是大端,传输时,统一用大端
  • 字符串,我们希望增加一个长度指示符,用于接收方计算字符串的实际长度
  • 浮点数,不同机器的表示格式不尽相同,我们将其转换为整数后,再发送

按面向对象的设计思想,我们自然会想到,将不同的类型,封装成不同的类。例如,CInt负责整数的大小端转换,CStr负责字符串的处理,CFloat负责将浮点数转换为64位的整数值。

接下来,我们还需要定义一个Send函数,负责数据的发送:

template<typename T>
int Send(const T &t)
{
    MyFunc<T> s(t); //注意,这里的代码是不合法的,C++不支持这种语法,编译会报错

    //将s转换后的内容,发送出去
}

上面代码想实现的目标是:

  1. 入参T对应本机的实际类型int、char *、float等。
  2. Send中,先将t转换为对应的CInt、CStr、CFloat的实例,进行数据转换,然后,将转换后的数据,发送出去。

这里的关键点在于对s的类型声明,如果有一个类似MyFunc的“函数”,可以将输入类型T,转换为我们想要的CInt、CStr等类型的话,上面的代码就能通过编译了。

元函数定义

C++中并没有元函数的声明语法,在mpl中,是借用模板来实现的。

template<typename fld1> //元函数入参
struct MyFunc
{
    typedef ...... var1; //可使用typedef定义一些变量
    //std和mpl中,提供了一些标准模板,可实现类似条件判断、循环等操作

    typedef ...... type; //这个type就是元函数的返回结果,算是mpl中约定俗成的做法
};

在MyFunc这个模板类的“{}”内部,相当于是元函数的函数体,模板参数就是元函数的入参,type为出参。

而我们前面写的Send函数,就变成下面这个样子:

template<typename T>
int Send(const T &t)
{
    MyFunc<T>::type s(t); //区别就在这里

    //将s转换后的内容,发送出去
}

在真实世界中,元函数的实现往往不止一个模板定义,而是使用了模板部分特化技术,分多个模板实现。代码往往会分散在多个文件中,元函数更多只算是一种概念上的抽象。
如下样例所示:

//通用声明
template<typename fld1>
struct MyFunc
{
};
//针对每种类型的特化版本
template<>
struct MyFunc<int>
{
    typedef CInt type;
};
template<>
struct MyFunc<char *>
{
    typedef CStr type;
};
template<>
struct MyFunc<float>
{
    typedef CFloat type;
};

child类

child算是本次移植最核心的一个类,也是最有意思的一个类。
在C++中定义一个函数,形参个数是固定的,而且入参顺序也必须和定义完全一致。
但child却非常“另类”,并没遵循这个基本原则,构造时,参数可以随便输。
这种用法,我只在脚本语言中看到过。

为了实现以上用法,process通过下面这个特殊的构造函数,达到此目的:

// <boost/process/detail/child_decl.hpp>
class child
{
public:
    template<typename ...Args>
    explicit child(Args&&...args);
}

// <boost/process/child.hpp>
template<typename ...Args>
child::child(Args&&...args)
    : child(::boost::process::detail::execute_impl(std::forward<Args>(args)...)) {}

核心逻辑在execute_impl这个函数中,其位于“<boost/process/detail/execute_impl.hpp>”,此函数只是做了下字符串的转换,只要入参中包含一个unicode字符串,就将所有ansi字符串转为unicode字符串。然后,将转换后的参数转发给basic_execute_impl处理,而child构造的核心逻辑,就在此函数中。

child的构造过程

在Windows中,创建进程的API是CreateProcess
这个函数可以说是

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值