2008-09-02 26 views
10

其實,這個問題似乎有兩個部分:你會如何在C++中實現類似Erlang的發送和接收?

  • 如何實現模式匹配?
  • 如何實現send and receive(即Actor模型)?

對於模式匹配部分,我一直在尋找各種項目,如AppProp。這些看起來相當不錯,但無法讓他們在g ++的最新版本(4.x)上工作。 Felix語言似乎也很好地支持模式匹配,但並不是真正的C++。

至於Actor model,有喜歡ACT ++和Theron現有的實現,但對前者 我無法找到任何東西,但論文,而後者是單線程只 [查看答案。

就個人而言,我實現了使用線程和線程安全的消息隊列的演員。消息是類似散列的結構,並將它們與許多預處理器宏一起用於實現簡單模式匹配。

現在,我可以使用下面的代碼來發送消息:

(new Message(this)) 
    ->set("foo", "bar") 
    ->set("baz", 123) 
    ->send(recipient); 

而下面做簡單的模式匹配(qDebugqPrintable是Qt的特定):

receive_and_match(m) 
    match_key("foo") { qDebug("foo: %s", qPrintable(m->value("foo").toString())); } 
    or_match_key("baz") { qDebug("baz: %d", m->value("baz").toInt()); } 
    or_match_ignore 
end_receive 

但是,這對我來說看起來有點不好,而且不夠健壯。

你會怎麼做?我錯過任何現有的工作嗎?

回答

4

一個關於二郎山重要的事情是怎樣的功能是用來做強大的系統。

發送/接收模式不分享,並且明確複製。 進程本身是輕量級線程。

如果你沒有慾望二郎神模型的穩健性,你最好使用真正的流程和IPC而不是線程。

如果你想健壯的消息傳遞,雖然你可能會想序列化和deserialise內容。特別是對於類型安全。

模式在C++匹配並不總是漂亮,但會有這種的良好格局 - 你最終將建立一個使用某種形式的多態性,以得到你想要的一個調度員對象。

但如果你不小心,你在管:)

結束了XML真的,如果你想Erlang的模型,你真的想用二郎。如果有緩慢的位,我相信你可以使用外部函數互聯網來擴充你的程序。

關於重新實現部分的問題,你是不會得到良好的凝聚力圖書館和解決方案。你已經看到的解決方案已經不再像C++了。

11

對於Actor模型,也有像 ACT ++ 和塞隆現有的實現,但我找不到 什麼,但論文前者,並 後者是單線程只。

作爲Theron的作者,我很好奇爲什麼你認爲它是單線程的?使用線程和線程安全 消息隊列

這就是塞隆是如何實現的

就個人而言,我實現了演員 .. :-)

+0

說實話,我不知道爲什麼我認爲Theron是單線程的。重新閱讀網站並不能給我那種印象。我爲這種困惑而道歉,我認爲如果我再給塞隆一次,這將是公平的! – 2008-11-03 17:03:02

+0

在Matlab mex文件中使用Theron for Actors併發性獲得了愉快的體驗。 – Chinasaur 2011-09-03 00:36:16

4

我目前正在使用「類型匹配」實現一個名爲「acedia」的C++演員庫(谷歌上沒有任何關於它的內容)。該圖書館是我的碩士論文的一個項目,您可以將任何類型的數據發送給演員。

一個小片段:

recipient.send(23, 12.23f); 

而且接收者方面,你可以分析這樣收到的消息:

Message msg = receive(); 
if (msg.match<int, float>() { ... } 

...或者你可以定義調用規則集功能或方法:

void doSomething(int, float); 

InvokeRuleSet irs; 
irs.add(on<int, float>() >> doSomething); 
receiveAndInvoke(irs); 

也可以在類型和值上進行匹配:

Message msg = receive(); 
if (msg.match<int, float>(42, WILDCARD) { ... } 
else if (msg.match<int, float>() { ... } 

常數「WILDCARD」表示任何值都將被接受。通過沒有參數是相等的所有參數設置爲「WILDCARD」;這意味着你只想匹配類型。

這當然是一個小片段。你也可以像Scala一樣使用「case class」。它們與erlang中的「原子」相當。這裏是一個更詳細的例子:

ACEDIA_DECLARE_CASE_CLASS(ShutdownMessage) 
ACEDIA_DECLARE_CASE_CLASS(Event1) 
ACEDIA_DECLARE_CASE_CLASS(Event2) 

反應的定義case類,你可以寫一個這樣的演員:

class SomeActor : public Actor 
{ 

    void shutdown() { done = true; } 
    void handleEvent1(); 
    void handleEvent1(); 

    public: 

    SomeActor() : done(false) { } 

    virtual void act() 
    { 
     InvokeRuleSet irs; 
     irs 
     .add(on<ShutdownMessage>() >> method(&SomeActor::shutdown)) 
     .add(on<Event1>() >> method(&SomeActor::handleEvent1)) 
     .add(on<Event2>() >> method(&SomeActor::handleEvent2)) 
     ; 
     while (!done) receiveAndInvoke(irs); 
    } 

}; 

要創建一個新的演員和啓動它,你必須寫是:

Acedia::spawn<SomeActor>(); 

雖然庫甚至沒有達到測試體育場所示的片段工作,我有第一個應用程序運行它。該庫的一個主要目標是支持分佈式編程(也可以通過網絡)。

你的問題是前一陣子,但如果你對它感興趣:讓我知道! :)

+0

我絕對有興趣;它看起來很不錯。有沒有可以下載圖書館/查看文檔的網站?你會開源嗎? – 2009-06-05 14:43:35

0

我一定會有興趣看看你的「acedia」圖書館,並願意以任何方式提供幫助。 Erlang有一些非常好的構造,C++肯定可以從這樣一個庫中受益。

2

您可以使用Qt的信號/插槽機制模仿行爲,尤其是因爲Qt的信號/插槽支持多線程。

0

今天,如果你想在C++中使用erlang風格的強壯的演員,並且模式匹配, 也許Rust就是答案。

當然這不是公開的,當OP問到5年前時,到2014年4月仍然不是v1.0 - 但它的進展非常好,而且絕對穩定,足夠的語言我認爲核心是穩定的。除了它支持輕量級任務,默認情況下沒有共享內存(然後提供用於共享的受控庫功能 - 「Arc」),它不像C++那樣具有與內存管理相同的方法。 它可以直接調用(並直接顯示)'extern C'函數。您不能與C++共享模板庫頭文件 - 但您可以編寫模仿C++集合類的泛型(以及反之亦然),以將引用傳遞給數據結構。