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。

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

  • 相关阅读:
    HTML DOM 12 表格排序
    HTML DOM 10 常用场景
    HTML DOM 10 插入节点
    HTML DOM 09 替换节点
    HTML DOM 08 删除节点
    HTML DOM 07 创建节点
    022 注释
    024 数字类型
    005 基于面向对象设计一个简单的游戏
    021 花式赋值
  • 原文地址:https://www.cnblogs.com/wpcockroach/p/2800491.html
Copyright © 2011-2022 走看看