zoukankan      html  css  js  c++  java
  • Theron, a lightweight C++ concurrency library, 源码分析(一)

    Theron是一个基于Actor Model的轻量级C++并行库(Theron is a fast, portable, lightweight C++ concurrency library based on Actor Model)。

    在分析Theron源代码前,先简单说一说Actor Model到底是一个什么东西。

    Actor Model

    Actor Model是一种并发模型,详细的信息你可以在wiki上找到。如果你觉得英文比较难理解,也可以看看老赵的博客,他写了3篇关于Actor Model的博文(123)。可以说,看完这三篇文章,你应该能够对Actor Model建立一个直观的认识。

    我个人觉得并行编程的模型强调了一点,不要使用简单的线程来解决并发的问题,因为不容易处理好锁与锁之间的关系。要从整体业务上来考虑问题,以一个一个关联不是很紧密的流程为基础来进行并发。也就是说,以task为基础进行并发。

    说到这,前戏算是完了,我们进入正题。。。。

    在Theron中,或者说在Actor Model中有几个重要的概念,它们分别是:

    • Actor
    • Message
    • Address
    • Mailbox

    Actor就不多说了。在Actor Model中,万事万物皆actor。和面向对象中强调万事万物皆对象是一样的。

    Message就是消息吧。在Actor Model中,actor与actor之间通过消息进行通信。那么actor如何将指定的消息发送给它想通知的其他actor呢?靠Address。

    Address就是地址,更严格地说是mailbox的地址。Actor和actor只能通过地址相互通信。因此,如果两个actors相互不知道对方的地址,那么它们就无法相互发送消息。接收消息的actor可以从message中提取到发信actor的地址。

    Mailbox就是邮箱,用来存放收到的消息。

    所以,Actor Model可以形象地理解成人和人之间相互寄信。人就是actor,信就是message,家庭地址就是address,邮箱就是mailbox,信封上有寄信人的地址。也正因为这种类比,我们可以想象:

    • 不同actor之间是并行执行的
    • Actor可以顺序执行收到的消息,也可以并行执行。一般来说,顺序执行比较容易实现

    在Theron中,除了上面4个重要的类之外,还有一个类也很重要,就是Framework类。事实上他有点像邮局。

    既然Theron是一个并发库,那势必还要有线程相关的类。直接和线程相关的有4个,他们分别是:

    • Thread
    • ThreadContext
    • WorkerThreadStore
    • ThreadPool

    间接关联的有一个:

    • ProcessorContext

    我们先从线程相关的类开始说起。

    Thread and ThreadPool

    Thread class

    根据运行环境的不同,Theron通过宏定义区别出了3种实现Thread类的方法,分别是:

    • 基于Win32 API的实现
    • 基于boost::thread的实现
    • 基于C++11 std::thread的实现

    你要定义一个具体的业务处理函数,该函数会在特定实现中的线程里被调用。

    主要的几个成员函数是:

    • Start(EntryPoint entryPoint, void* context)
    • Join

    ThreadContext struct

    这个结构是ThreadPool中的内部被定义的。所以可以知道它和ThreadPool的关系要比Thread类和ThreadPool的关系来得更紧密。事实上也是这样的。ThreadPool所管理的具体线程事实上是通过ThreadConext来进行的。所以确切地说,线程池中的线程在这里指ThreadContext更恰当些。

    先来看下它的具体定义。

       1: struct ThreadContext
       2: {
       3:     WorkerContext* mWorkerContext;
       4:  
       5:     WorkQueue* mWorkQueue;
       6:     uint32_t   mNodeMask;
       7:     uint32_t   mProcessorMask;
       8:     bool       mRunning;
       9:     bool       mStarted;
      10:     Thread*    mThread;
      11: };

    这里有2个东西可能比较困惑。一是,WorkerContext;二是,WorkQueue。除此以外,应该没有不难理解的东西。WorkerContext和WorkQueue暂时先搁置下,等讲到ThreadPool线程池的时候我们再来说这两个东西。

    ThreadPool class

    说到ThreadPool,我想大家应该都不怎么陌生。在操作系统级别都提供了线程池相关的函数。这里需要强调一点的是,Theron中线程池中的线程不是Thread而是ThreadContext。为什么这么说?等到说Framework类的时候,你就更清楚了。

    ThreadPool是一个模版类。

       1: template <class WorkQueue, class WorkProcessor, class WorkerContext>
       2: class ThreadPool;

    这个类在Framework类中被这样使用:

       1: typedef ThreadSafeQueue<Mailbox> WorkQueue;
       2: typedef ThreadPool<WorkQueue, WorkItem, WorkerThreadStore> ThreadPool;

    所以,ThreadContext中的WorkQueue就是ThreadSafeQueue<Mailbox>类型,WorkerContxt就是WorkerThreadStore类型。WorkerThreadStore会在后面介绍,现在你可以认为他是工作线程保存相关信息的一个storage。

    ThreadPool提供了几个重要的成员函数。

    CreateThread(ThreadContext* threadContext)

    创建一个Thread对象并把句柄保存到threadContext->mThread中。

    StartThread(ThreadContext* threadContext, WorkQueue* workQueue, …)

    启动线程。总共4个参数,这里罗列了前两个最重要的。

    StartThread将workQueue保存到threadContext->mWorkQueue中,然后通过threadContext->mThread->Start启动线程,在线程中处理workQueue中的mailbox。

    传递给Start函数的第一个参数EntryPoint是这样定义的:

       1: void ThreadEntryPoint(void* context)
       2: {
       3:     ThreadContext* threadContext(reinterpret_cast<ThreadContext*>(context));
       4:  
       5:     threadContext->mStarted = true;
       6:  
       7:     uint32_t backoff(0);
       8:     while (threadContext->mRunning)
       9:     {
      10:         if (typename WorkQueue::ItemType* item = threadContext->mWorkQueu->Pop())
      11:         {
      12:             WorkProcessor::Process(item, threadContext->mWorkerContext);
      13:             backoff = 0;
      14:         }
      15:         else
      16:         {
      17:             Utils::Backoff(backoff);
      18:         }
      19:     }
      20: }

    ItemType就是Mailbox。WorkProcessor在这里是WorkItem类。至于WorkItem::Process到底做了什么事情,还是留等后面我们对Theron了解更深入了之后再进行深入分析。这里你只要知道线程池道理这里就是逐一处理Mailbox里的信息了。

    另外,这里还要注意的一个点是这里的while是一个死循环。所以当线程池把线程启动之后,除非特定操作,不然这个线程是不会退出的。

    线程池类还提供了StopThread和DestroyThread两个函数,这里就不多做介绍了。

    WorkerThreadStore and ProcessorContext

    这两个结构放到后面再议。

    说完了线程相关的内容,我们开始介绍Theron中和Actor Model概念有密切联系的几个类。先说Framework。

    先到这里。。。未完待续。。。

  • 相关阅读:
    31天重构学习笔记23. 引入参数对象
    31天重构学习笔记31. 使用多态代替条件判断
    31天重构学习笔记25. 引入契约式设计
    新加坡面试经历
    Release a AutoUpdater tool
    31天重构学习笔记24. 分解复杂判断
    31天重构学习笔记29. 去除中间人对象
    自动更新组件分享
    WPF基础到企业应用系列7——深入剖析依赖属性(WPF/Silverlight核心)
    (收藏)2010年度十大杰出IT博客
  • 原文地址:https://www.cnblogs.com/wpcockroach/p/2800491.html
Copyright © 2011-2022 走看看