C++併發程式設計框架Theron(4)——Hello world!

無鞋童鞋發表於2017-07-16

1 前言
  上一篇博文我主要介紹了Theron框架實踐的入門知識,也就是如何搭建Theron框架環境以及各種編譯時候的配置選擇。從這篇博文開始,我們開始真正去了解如何編寫Theron框架的程式。和其他語言學習一樣,我們還是以經典的Hello world!列印作為Theron框架學習的入門程式,麻雀雖小五臟俱全,你會通過它學到Theron中執行緒間訊息通訊是如何實現的等等基本內容。
2 Hello world!
  儘管Theron功能十分強大,但是它使用起來也十分簡單。Hello world!一個小小例子,大多需要知道的內容就可以提前學習到了。
  程式中,我們會建立一個簡單的actor,當它收到訊息自動調動訊息處理函式來列印訊息內容。此處我們將傳送的訊息是std::string型別,當actor收到一條std::string訊息(程式中正是“Hello world!”),它就會自動立即列印出該內容。程式實現,一開始我們包含主要的Theron標頭檔案:

#include <Theron/Theron.h> 

  接著,我們定義一個Printer actor。每個actor實質就是一個繼承自Theron::Actor的C++類:

// 完成列印字串的Actor 
// 繼承自Theron::Actor. 
class Printer : public Theron::Actor 
{ 
public:
    // 結構體, 傳遞framework給基類 
    Printer(Theron::Framework &framework) : Theron::Actor(framework) 
    { 
        // 註冊訊息處理函式 
        RegisterHandler(this, &Printer::Print); 
    } 
private:
    // std::string型別的訊息處理函式 
    void Print(const std::string &message, const Theron::Address from) 
    { 
        // 列印字串 
        printf("%s\n", message.c_str()); 
        // 返回一個虛假(dummy)訊息來實現同步 
        Send(0, from); 
    } 
}; 

  我們可以認為一個actor就是一個具體型別的物件。不像傳統的C++物件,actors和呼叫處後面的程式是並行非同步執行的,溝通完全依靠訊息。
  建立一個傳統的C++物件,Printer類應該擁有一個公共方法叫做Print()用來接受std::string的引數。但是與之相反,這個叫Printer的actor並不包含公共方法,替換的是註冊一個訊息處理函式叫做Print()。處理函式是通過Printer建構函式來註冊的,並且它會在任何收到一條std::string型別的訊息的時候被立即執行。
  在程式中,Print()訊息處理函式會傳送一條虛假訊息(一個int型別的0值)返回給傳送者,用來實現同步。後面我們再討論原因。
  上面已經定義了我們自己的actor,讓我們在一個簡單的程式中使用它:

int main() 
{ 
    // 構造一個framework物件,並且例項化一個Printer的actor由它管理. 
    Theron::Framework framework; 
    Printer printer(framework); 
    // 構造一個receiver物件來接收actor的反饋訊息 
    Theron::Receiver receiver; 
    // 傳送一條訊息給Printer. 
    // 我們傳遞receiver的地址當做'from'的地址 
    if (!framework.Send( 
        std::string("Hello world!"), 
        receiver.GetAddress(), 
        printer.GetAddress())) 
    { 
        printf("ERROR: Failed to send message\n"); 
    } 
    // 使用虛假訊息來實現同步,確保所有執行緒完成任務
    receiver.Wait(); 

  首先我們建立一個Theron::Framework,並且在其中建立一個我們Printer的actor例項。Framework是一個作為actors宿主的管理類,並且這裡我們傳遞它給actor建構函式。
  我們同時也會建立一個Theron::Receiver類,它可以看做是一位好心人,由於主函式沒有當做actor註冊的訊息,所以它需要一個有家庭地址的“人”替它代收訊息,Theron::Receiver類正是幹這個活的。它的地址會用來接收actors反饋回來的訊息。
  一切準備完畢,我們傳送一條訊息“Hello world!”給Printer讓其列印。呼叫Framework::Send()是非阻塞的,它會在傳送完訊息後立即返回。以此同時,Print()訊息處理函式會同步被一個與Printer actor關聯的獨立執行緒執行。
  非同步訊息傳遞的使用時Actor模型的核心思想。如果這裡是通過一個傳統的C++物件完成Printer,其中包含一個Print()方法,會請求一個外執行緒去同時訪問actor的內部狀態,使得這個actor變成非執行緒安全的物件。相反,Actor模型中Printer的內部狀態僅可以被用來執行它的訊息處理函式的執行緒所接近。Theron只可以一次執行每個actor的一個訊息處理函式,而收到的訊息是序列排列來處理的。所以每個actor是與生俱來地執行緒安全的,甚至當同時通過多個客戶端傳送多條訊息。
  當通過Framework::Send()傳送一條訊息,我們需要提供兩個地址:一個傳送者的地址和一個接收者的地址。這裡我們將本地的Receiver作為“from”地址,從而Printer可以傳送一條確認訊息給receiver,告訴它列印的任務已經完成了。
  主執行緒塊呼叫了一次Receiver的Wait()方法,用來等待接收到actor的反饋訊息才結束主執行緒,也就是整個程式。
  這塊我們還是需要好好理解一下為什麼需要一個Receiver物件。如果我們沒有構造它,那麼主執行緒執行到main()的結尾,從而會在Printer處理訊息結束之前開始析構那個actor和framework。這樣可能性的出現時因為Printer非同步執行,並且與主執行緒並駕齊驅的。我們通過等待反饋訊息的到來引入一些同步:同步actor的訊息處理函式的結束來確保執行緒的結束。
3 小結
  在這個“Hello world!”例項中,我們通過程式瞭解了之前理論學習中幾個重要的概念:actors,frameworks,messages和receivers。這幾個物件是Theron框架簡單程式實現的關鍵,也是複雜程式的基礎單元。在後面,我們會接觸更多的Theron框架的細節。
  以上是個人學習記錄,由於能力和時間有限,如果有錯誤望讀者糾正,謝謝!
  轉載請註明出處:http://blog.csdn.net/FX677588/article/details/75194617


  參考文獻:
  Theron框架官網http://www.theron-library.com/

相關文章