3

通常のクラス メソッドを介して現在の状態を公開することにより、ブロッキング コンテキストからクラス ベースのアクターの状態にアクセスしたいと考えています。最善のアプローチは何ですか?主な方法として、次の 3 つが考えられます。

  1. クラスベースのアクターは、メッセージの受け渡し以外で自分の状態を公開すべきではありません (つまり、最初から何か間違ったことをしています)。
  2. クラス メソッドscoped_actorは、クラス ベースのアクターにメッセージを送信し、応答を返すために を使用する必要があります。
  3. クラス メソッドはアクター フレームワークをバイパスし、状態を保持するメンバー変数にアクセスする必要があります。

アプローチ #2 を試みましたが、「mutable」キーワードを追加してキャプチャされた変数を変更する方法を理解しましたが、デッドロックを作成せずにキャプチャされた変数を設定できるようになるまで、メソッドの戻りを遅らせることができませんでした。

アプローチ #3 は、以下に示した例でうまくいくようです。保護されたアクセスと保護されていないアクセスの両方が機能しているように見えたので、状態へのアクセスを保護する必要があるかどうかはわかりません。

using size_atom = atom_constant<atom("size")>;
using done_atom = atom_constant<atom("done")>;
using a_type = typed_actor<
    replies_to<int>::with<void>,
    replies_to<size_atom>::with<size_t>,
    replies_to<done_atom>::with<void>>;

class A : public a_type::base
{
public:
    size_t size_direct_access()
    {
        return this->m_values.size();
    }

    size_t size_protected_access()
    {
        lock_guard<mutex> lock(this->m_mutex);
        return this->m_values.size();
    }
protected:
    behavior_type make_behavior() override
    {
        return
        {
            [this](int value)
            {
                lock_guard<mutex> lock(this->m_mutex);
                this->m_values.push_back(value);
            },
            [this](size_atom) -> size_t
            {
                lock_guard<mutex> lock(this->m_mutex);
                return this->m_values.size();
            },
            [this](done_atom)
            {
                this->quit();
            }
        };
    }
private:
    vector<int> m_values;
    mutex m_mutex;
};

void tester()
{
    a_type testeeActor = spawn_typed<A, detached>();
    abstract_actor* abstractActor = actor_cast<abstract_actor*, a_type>(testeeActor);
    A* a = dynamic_cast<A*>(abstractActor);
    scoped_actor self;
    self->sync_send(testeeActor, 5).await(
        [a, testeeActor, &self]()
        {
            size_t direct_access = a->size_direct_access();
            size_t protected_access = a->size_protected_access();
            aout(self) << "Direct: " << direct_access << " Protected: " << protected_access << endl;

            self->sync_send(testeeActor, 3).await(
                [a, testeeActor, &self]()
            {
                size_t direct_access = a->size_direct_access();
                size_t protected_access = a->size_protected_access();
                aout(self) << "Direct: " << direct_access << " Protected: " << protected_access << endl;

                self->sync_send(testeeActor, 1).await(
                    [a, testeeActor, &self]()
                {
                    size_t direct_access = a->size_direct_access();
                    size_t protected_access = a->size_protected_access();
                    aout(self) << "Direct: " << direct_access << " Protected: " << protected_access << endl;

                    self->sync_send(testeeActor, done_atom::value);
                });
            });
        });
}

int main()
{
    cout << "Spawning actors" << endl;
    tester();
    cout << "Awaiting all actors done" << endl;
    await_all_actors_done();
    cout << "Shutdown" << endl;
    shutdown();
    cout << "Press Enter to continue" << endl;
    cin.get();
}
4

1 に答える 1

4

あなたは最初にあなた自身の質問に答えています:

クラスベースのアクターは、メッセージの受け渡し以外で自分の状態を公開すべきではありません(つまり、最初から何か間違ったことをしています)。

アクターは、メッセージ パッシングを介してのみ通信します。この原則に違反しようとしてはなりません。そうしないと、ランタイムによって提供されるすべての安全保証が失われます。共有された変更可能な状態が必要な場合、アクター モデルは不適切なプリミティブです。

つまり、共有された不変状態はアクター モデルでうまく機能します。const 参照をアクター コンストラクターに渡して外部スコープと共有状態にすることはできますが、参照がアクターの存続期間中有効であることを確認する必要があります。もう 1 つのオプションは、要素にコピー オン ライト インターフェイスを提供することによって、共有された不変データの概念をカプセル化するメッセージを使用することです。

アップレベリング: アクターからデータにアクセスする必要がある場合は、プログラムの設計を再検討する必要があります。

于 2015-11-20T20:28:27.527 に答える