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的博文(1,2,3)。可以說,看完這三篇文章,你應該能夠對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。
先到這里。。。未完待續。。。