上篇日志提到我想用 ACE 和 Loki 库设计一个类似 OpenMP 的并行库,前两天仔细想了想,勾勒出了大体的框架,以供讨论;)
看下面代码之前,首先要熟悉 Loki 库里面对 Functor 模板类的使用(《 C++ 设计新思维》一书有详细描述,不过看此书要做好心理准备:)),否则看了也是一头雾水; ACE 的部分暂未描述出来,先将其隐藏在 ParallelTask 类当中,所以对 ACE 不了解也没关系。
结合下面代码,先把各个类的功能说一下:
(1) 函数Task1、仿函数Task2和类Task3中的成员函数 这三种形式基本列出了C++中具有函数功能的几种表示形式,而执行一个函数就是执行一项任务。下面都将以任务的概念来描述串行和并行。另外,这里返回值都 用了void,并且没有传入传出参数是因为这些都是抽象出来的概念,最终总是有办法把任务抽象到这几种形式的。
(2)关于typedef Loki::Functor<> SerialTask,这里用了 Loki::Functor<>,详细的我不解释了,看书吧,大概的用处就是用了这个模板类,可以把上面三种(实际有更多)函数形式完美的包装进去,令函数执行 的 预 备工作(准备对象和输入参数等等这些事情)和执行过程(就是执行函数体)分离开来,这样我们就可以把任务的准备期和执行期很好的分离,方便宏观设计。如果 了解设计模式中的Command模式,应该会很快领悟到。另外利用一个Chain模板函数,此模板类还可以把各个任务方便的串行起来,以实现串行功能,故 在此将其typedef为 SerialTask。
(3)关于类 ParallelTask ,顾名思义,这个类就是具有并行功能类,我可以通过其PushTask成员函数方便的把任务塞给它,这些任务都将并行执行。而让它们何时执行,可以通过调用 operator()来触发。此类也可以当作一个任务(由众多小任务组成)来看待,而且有了operator(),也可以方便的交由SerialTask对象来将它与其它任务串行起来。这个类背后的实现会用到ACE,因为ACE本身具有很强大的跨平台的多线程库。
(4) Sample1_2_3() 、 Sample1_23() 、Sample1_23() 、 Sample123() 是我写的几个例子,通过这几个例子可以更容易理解我的设计意图。
void Task1();
struct Task2
{
void operator()();
};
struct Task3
{
void MemberFun();
};
typedef Loki::Functor<> SerialTask;
class ParallelTask
{
public:
ParallelTask(bool bWait = true);
void operator()();
void PushTask(const SerialTask& st);
private:
vector<SerialTask> m_serialTaskVec;
bool m_bWait;
};
SerialTask subTask1(Task1); // subTask1对象将会运行Task1()函数。
Task2 t2;
SerialTask subTask2(t2); // subTask2对象将会运行t2(),也就是执行t2::operator()。
Task3 t3;
SerialTask subTask3(&t3, &Task3::MemberFun); // subTask3对象将会t3.MemberFun()。
SerialTask subTask1_2(Chain(subTask1, subTask2)); //subTask1_2对象将会串行执行subTask1和subTask2,也就是先执行Task1(),接着执行t2::operator()。
SerialTask subTask1_2_3(Chain(subTask1_2, subTask3)); //subTask1_2_3对象将会串行执行subTask1、subTask2和subTask3,也就是先执行Task1(),接着执行t2::operator(),最后执行t3.MemberFun()。
// 此函数通过调用subTask1_2_3()来串行执行任务1,2,3
void Sample1_2_3()
{
subTask1_2_3();
}
// 此函数表示先执行任务1,然后并行执行任务2和3
void Sample1_23()
{
ParallelTask pt;
pt.PushTask(subTask2);
pt.PushTask(subTask3);
SerialTask st(Chain(subTask1, pt)); // 注意此处pt作为一个串行任务加入进去
st();
}
// 此函数表示并行执行任务1,2和3
void Sample123()
{
ParallelTask pt;
pt.PushTask(subTask1);
pt.PushTask(subTask2);
pt.PushTask(subTask3);
pt();
62. }