10

実際、この質問には 2 つの部分があるようです。

  • パターンマッチングの実装方法は?
  • 送信と受信(つまり、アクター モデル)を実装する方法は?

パターン マッチングの部分については、 AppPropなどのさまざまなプロジェクトを調べてきました。これらはかなり良さそうに見えますが、最近のバージョン (4.x) の g++ では動作しませんでした。Felix言語もパターン マッチングをかなりうまくサポートしているように見えますが、実際には C++ ではありません。

Actor モデルに関しては、 ACT++ やTheronなどの既存の実装がありますが、前者に関する論文しか見つかりませんでした。後者はシングルスレッドのみです[回答を参照]。

個人的には、スレッド化とスレッドセーフなメッセージ キューを使用してアクターを実装しました。メッセージはハッシュのような構造であり、これらを多数のプリプロセッサ マクロと組み合わせて使用​​して、単純なパターン マッチングを実装しました。

現在、次のコードを使用してメッセージを送信できます。

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

そして、単純なパターン マッチングを行うには、次のようにします (qDebugおよびqPrintableQt 固有です)。

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

7 に答える 7

10

アクターモデルに関しては、ACT++やTheronなどの既存の実装がありますが、前者は論文しかなく、後者はシングルスレッドのみです。

Theron の作成者として、なぜそれがシングルスレッドであると信じているのか知りたいのですが?

個人的には、スレッド化とスレッドセーフなメッセージ キューを使用してアクターを実装しました。

それがTheronの実装方法です.. :-)

于 2008-10-08T22:17:26.050 に答える
4

erlangの重要な点の1つは、堅牢なシステムを作成するために機能をどのように使用するかです。

送信/受信モデルは共有せず、明示的にコピーします。プロセス自体は軽量スレッドです。

erlangモデルの堅牢なプロパティが必要な場合は、スレッドではなく実際のプロセスとIPCを使用するのが最適です。

堅牢なメッセージパッシングが必要な場合は、コンテンツをシリアル化および逆シリアル化する必要があります。特に型安全性について。

C ++でのパターンマッチングは必ずしもきれいではありませんが、これには適切なパターンがあります。最終的には、何らかの形のポリモーフィズムを使用して必要なものを取得するディスパッチャーオブジェクトを作成します。

注意しないと、パイプを介してxmlになってしまいますが:)

本当に、erlangモデルが必要な場合は、本当にerlangを使用したいと思います。遅いビットがある場合は、外国の機能のインターネットを使用してプログラムを拡張できると確信しています。

パーツの再実装に関する問題は、優れたまとまりのあるライブラリとソリューションが得られないことです。あなたがすでに持っているソリューションは、もはやC++のようには見えません。

于 2008-09-02T20:49:18.967 に答える
3

私は現在、「タイプマッチング」を使用する「acedia」と呼ばれるC++用のアクターライブラリを実装しています(Googleにはまだ何もありません)。ライブラリは私の修士論文のプロジェクトであり、あらゆる種類のデータをアクターに送信できます。

小さなスニペット:

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 のように「ケース クラス」を使用することもできます。これらは、erlang の「アトミック」に相当します。より詳細な例を次に示します。

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

定義されたケース クラスに反応するには、次のようなアクターを記述できます。

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>();

ライブラリはベータ スタジアムにさえ達していませんが、表示されているスニペットは動作し、最初のアプリケーションが実行されています。ライブラリの主要な目標の 1 つは、分散プログラミング (ネットワーク経由でも) をサポートすることです。

少し前の質問ですが、興味があれば教えてください!:)

于 2009-05-26T20:14:00.583 に答える
2

特にQtのシグナル/スロットはマルチスレッドをサポートしているため、Qtのシグナル/スロットメカニズムを使用して動作を模倣できます。

于 2010-11-10T00:29:37.650 に答える
0

私はあなたの「acedia」ライブラリを見てみたいと思っており、できる限りお手伝いしたいと思っています. Erlang にはいくつかの素晴らしい構造があり、C++ はそのようなライブラリから確実に利益を得ることができます。

于 2009-05-30T04:52:44.390 に答える
0

今日、C++ で erlang スタイルの堅牢なアクターとパターン マッチングが必要な場合は、おそらく Rust がその答えです。

もちろん、OP が 5 年前に尋ねたとき、これは公にはありませんでした。2014 年 4 月の時点ではまだ v1.0 ではありませんが、非常に順調に進んでおり、確実に安定しています。言語コアは十分に安定しています考える。

C++ ではありませんが、C++ と同じメモリ管理のアプローチをとっていますが、デフォルトで共有メモリを持たない軽量タスクをサポートする点が異なります (その後、共有用に制御されたライブラリ機能を提供します - 「Arc」)。「extern C」関数を直接呼び出す (および直接公開する) ことができます。テンプレート化されたライブラリ ヘッダーを C++ と共有することはできませんが、C++ コレクション クラスを模倣するジェネリックを記述して (逆も同様)、データ構造への参照を渡すことができます。

于 2014-04-17T08:01:26.713 に答える