CERL2 经过一段时间的发展,已经稳定下来,是时候揭开它的面纱了。和 CERL2 最初设想并不一样,CERL2 最终没有成为一种语言,它在 CERL 上进行了编程模型的演化,并且形成了多个子库。最主要的两个子库为 async 和 venus。最底层的是 async,它需要针对不同的平台进行包装,以此形成一个网络层。你可以 拿 async 和 boost asio 类比,两者确实是类似的东西,只是编程理念不同。而 venus 是基于 async 之上的,一个平台无关的网络编程模型,这个模型是基于 Erlang Style Concurrency 观念的一个变种,它试图消除 Erlang 编程模型的一些缺陷。
本文是 CERL2 系列介绍的第1篇。按照惯例,我们写一个 Hello CERL2。代码看起来是这样的:
#include <async/Application.h> void cerl_callback hello(LPVOID lpParam) { cerl::FiberParam p(lpParam); printf("Hello, CERL2!/n"); p.service->quit(); } int main() { cerl::Application app; app.run(hello); }
在 CERL2 中,我们一个最基础的概念是 Fiber(纤程)。它类似erlang中的进程(Process),是一个轻量级的执行体。上面 hello 函数就是一个纤程 。它打印 Hello, CERL2! 后,退出整个程序。请注意 p.service->quit() 这句并不是退出纤程,而是退出 app.run(hello) 内部的循环。
要启动多个纤程,用 startFiber 函数:
#include <async/Application.h> void cerl_callback hello(LPVOID lpParam) { cerl::FiberParam p(lpParam); printf("Hello, CERL2!/n"); } void cerl_callback test(LPVOID lpParam) { cerl::FiberParam p(lpParam); cerl::startFiber(p.self, hello); cerl::startFiber(p.self, hello); p.service->quit(); } int main() { cerl::Application app; app.run(test); }
这个程序先启动了test纤程,然后test在运行中启动了2个hello纤程。程序运行结果是打印两句 Hello,CERL2!。
至此,Fiber 的基本用法已经会了。很简单吧?
那么 cerl::FiberParam 类用于干什么的?这个类从角色来说只是辅助类。但是又非常关键。其功用在于:
这里又带了了新概念:IoService。这个我们下回接着聊。对于上面介绍的内容,可能你最大的一个疑问是为什么不把 cerl::FiberParam 这个类隐藏起来。这当然是可能的,无非就是纤程的原型改为:
void cerl_callback FiberProc(cerl::Fiber* self, LPVOID val);
其中 cerl::IoService 是可以通过 self 取到的,所以可以不传入。
我的回答是,个人习惯而已。async 是底层库,我的习惯是包装得越薄越好。在这个 startFiber 之上,你完全可以自己写一个 spawn 函数,将 cerl::FiberParam 这个细节隐藏。这个包装手法很简单,我就不在这里罗嗦了。