C++并发编程框架Theron(2)——Theron的五要素

时间:2022-03-29 17:59:42

1 前言
  第一章主要介绍了Theron框架的基础知识以及其核心Actor模型,其中Actor模型凭借其与生俱来的高并发模式得到越来越多的关注。例如围绕其构建的Scala或ErLang语言,还有其它如Java语言中专门的Actor模型框架,本次Theron框架正是基于Actor模型构建的C++多线程开发框架。而在这篇博文中,我还是延续上一篇博文拓展介绍Theron框架的五要素,这也是Theron框架最基础的内容,下面我们直接进入正题。
2 Theron框架五要素
  2.1 Actor模型
  第一章已经描述过Actor模型的消息通信机制以及高并发执行的优势,成功的避开了互斥体和锁编程方式的困扰,可以说Actor模型就是Theron框架大厦的根基(相关的Actor模型理论我这里不再重复,请直接阅读系列博文的第一篇)。而借助传统共享内存的线程并发方式来构建多线程应用绝对是一个头痛的活,对于没有多线程开发经验的程序员而言简直是噩梦。
  2.2 actors
  actors是Theron程序的基础单元,就好比面向对象程序语言中的对象objects,但是所有actors之间是天生并行独立的,不可以有直接调用其他对象的行为,只能通过消息相互通信,这与类对象object存在很大的不同,如下图所示。


C++并发编程框架Theron(2)——Theron的五要素
图1 actors之间相互独立,通过消息机制相互通信  

  每个actor有自己唯一区别的名字和地址,这个地址是唯一标志每个actor的标签,它们就是通过这个地址相互交换信息,就像人与人之间信件通信的家庭住址。而消息在发送的时候是拷贝一份再发出去的,也就是这个消息只是内容相同但是保存的地址是各自独立的,这样才能保证真正的内存独立。源码中有相应的获取各个actor的地址接口函数GetAddress(),所以每个actor的地址是可以轻松查询到的,这些内容我们后面再详细的介绍。 而为了确保消息在发送的时候可以被拷贝一份,所以Theron框架中可以相互通信的消息要求必须是可以被拷贝的对象,例如std::string或其他有拷贝构造函数的类对象等。
  2.3 消息处理器(Message Handlers)
  它定义了每个actor响应消息所要执行的程序,而这些程序是我们预先定义的私有成员函数。程序执行后,只要actors收到消息,它们的消息处理器就会对应被自动触发,并且被一个共享线程池并发执行。这里我们可以认为每个actor的整个生命周期就是由接收消息和响应消息组成,这个消息处理器就相当于每个actor的举止表现:会检验接收到的是什么消息,会更新内部状态,以及可能发送消息给其他actors。
  actors可以注册任何数量任何不同类型消息的处理器。相同,它们也可以注册任何数量的处理器来处理一种类型的消息。当一个actor收到一条消息,对应类型的消息就会被检测,并且所有对应消息类型的处理器被排程执行。消息处理器的排程确保一次至多有一个该actor的处理器能够执行。一个actor的所有处理器是假设被该actor包含的“虚拟”线程所执行的,而实际当中,这些处理器是被很多actors间共享的线程工作池所执行的。
  2.4 frameworks
  Theron允许被称为frameworks的子系统来统一组织管理actors。每个framework都拥有自己的一个线程池(thread pool),专门用来执行在其下注册的actors。而跨framework管理其他frameworks的actors是被禁止的。
  在每个framework被创建的时候,我们可以详细说明初始化线程数量,处理器关联性和frameworks的收益策略,并且允许为实时,低延时和时序要求严格的应用创建专用的frameworks。
  2.4.1 工作线程池
  此处我想重点介绍一下Theron的线程池,也就是解释一下frameworks在Theron框架中存在的必要性。前面已经介绍过了,每个actor都有一个自己独一无二的线程,这些线程是用来当actor无论什么时候收到一条消息,各种消息处理器能被其立即执行。如此一来,我们明显有一种方法来完成这个基于actor的系统:任何时间一个actor被构建,然后我们开启一个独立线程取完成这个actor的活。但是这样设计有个很大的缺点,就是很容易快速创建大量的线程,这自然是我们不希望看到的。所以在Theron系统中,actor的消息处理器是被一个固定的工作线程池所执行的。这中方法设计被称为M:N结构,即我们有M个并发实体,但是实际线程数量是N个,两者不对等。线程池中线程的数量可以在初始实例化framework对象时候设置,默认情况下是两个线程。
  一旦actors接收到消息,这些消息就会被按队排放在一个线程安全的工作队中(work queue),并且工作线程就会从线程池中被新到达的活唤醒。这个被唤醒的线程立即从队列中检索一个actor,并且执行这个actor接收到的某个类型的消息对应注册绑定的消息处理器。整个线程池检索过程如下图2所示。

C++并发编程框架Theron(2)——Theron的五要素
图2 线程池中线程检索actors的消息队列  

  这里需要注意下面几个地方:
  Ⅰ 一旦一个工作线程开始执行一个actor的消息处理器,它就会一直执行它们到结束,而不会半途切换到一个新的actor。这就意味着存在糟糕行为的(例如消息处理器容易卡死)的actors可以饿死整个系统中其他actors。例如默认线程池中有两个线程情况下,假设现在我们有三个actor,其中两个actors的消息处理函数处于死循环状态,那么线程池的两条线程就被它两个actors所霸占,另一个actor就会永远不会被执行。
  Ⅱ 为了确保actors不会被无期限的饿死,用户需要在程序中合理的考虑激活线程的数量(即线程池中线程的数量)。当然,此处线程数量越多,actors被饿死的概率越小,CPU利用率也会更高。但是受硬件物理核的限制,我们自然不可以无节制的增加线程的数量,过量线程只会增加线程过度切换的开销,这是程序设计得不偿失的。所以合理分配线程的数量才是最完美的,这个需要我们自己权衡是想更多线程并发执行还是想提高程序的效率。
  Ⅲ 假如我们为每个actor某个类型的消息注册绑定了多个消息处理器(处理函数),那么从线程池中被唤醒的一个线程会串行按注册顺序将这些消息函数依次都执行完成。 
  2.5 距离无限制特性
  因为Actor模型不会有别区分相邻和远距离的actors,所以各个远距离服务器上子应用间联系和同步是无缝对接的。在相同的进程中,消息传送可以很自然的在远程主机间运作,这个没有距离限制的特性使得Theron框架非常适合分布式应用开发,就像多线程程序开发一样简单。
4 小结
  这篇博文主要介绍了Theron框架的五要素,包括Actor模型,actors对象,frameworks,工作线程池以及距离无限制特性。这些事Theron框架的基础,可以大致了解一番,后面再根据实例慢慢体会每个要素的特性以及功能。在后面文章中,我也会慢慢转为实战和介绍程序,到此我相信你对Theron框架已经有了一个大致的了解了。
  以上是个人学习记录,由于能力和时间有限,如果有错误望读者纠正,谢谢!
  转载请注明出处:http://blog.csdn.net/FX677588/article/details/74936625


  参考文献:
  Theron框架官网http://www.theron-library.com/
  详解Theron通过Actor模型解决C++并发编程的一种思维http://www.mahaixiang.cn/bcyy/954.html