2

私の質問: データの整合性を気にせずに、説明されているクラスをより適切に設計するにはどうすればよいですか?

クラス Player-Container と Player があります。Player-Container は多かれ少なかれ集中化された Player "Data-Container" であり、すべてのスレッドがこのクラスへのポインタを持っています。TBB ライブラリは、読み取り専用および書き込み用のロック メカニズムを提供します。現在の設計を反映する擬似コードがいくつかあります。

Class: Player-Container 
Method: CreatePlayer, RemovePlayer , LoginUser, VerifyUser

Class: Player
Method: None its a pure data container

私が開発するほど、「トップレベルコンテナ」にこれらの機能を持たせるのは間違っているように思えますが、コンテナはオブジェクトをロックできることを保証し、並列アクセスがオブジェクトを変更できないようにするため、これを回避していないようです。ユーザー (例: ユーザーが何かをビルドし、このリクエストを 2 回送信すると、リソースが 1 回ではなく 2 回削減されます)。

私がしたいこと:

Class: Player-Container
Method: CreatePlayer, RemovePlayer

Class: Player
Method: LoginUser, VerifyUser,....

私の問題、どうすればそれを達成し、データの整合性を維持できますか? いくつかの入力と提案があるといいでしょう。私を最も悩ませているのは、PlayerContainer が実際に Player クラスについて多くのことを知る必要があることです。属性を変更すると、コンテナで多くのコードを書き直さなければなりません。

不明な点がある場合は、お問い合わせください。

4

2 に答える 2

2

ここでは、設計とロックに関する 2 つの質問があるようですが、カプセル化と結束に関しては、かなり明確に設計上の緊張が存在します。

API のユーザーからは、プレーヤーを追加/削除/ログインするために「Player-Container」クラスのみを処理する必要があることは確かに良いようです。

物事をシンプルに保つために、Player-Container で正面向きのメソッドを維持することを検討します。ただし、ヘルパー クラスまたはヘルパー関数を追加して実装し、Player-Container クラス内のコードがほとんどないようにすることも考えられます。必要に応じて、これらをメソッドとしてプレーヤー クラスに追加することもできます。

関数を配置する場所に関する Scott Meyer のこの記事をまだ読んでいない場合は、おそらく読む価値があります。

2 番目の質問は、ロックに関するものです。つまり、コンテナーまたはプレーヤー クラスのどこにロックを配置する必要があるかということです。

ここには選択肢がありますが、コンテナと個々のクラスのデータの両方を同期する必要があることに注意してください。そのため、並行コンテナーを使用してプレーヤーを保持し、プレーヤー コンテナー クラスでの重いロックを回避する場合、特に複数のスレッドが同じプレーヤーで動作できるようにする場合は、プレーヤー クラスが確実に同期されるようにする必要があります。

これを行う場合は注意してください。プレーヤーの個々のメソッドをロックするのではなく、プレーヤー全体をロックして、互換性のない機能をインターリーブしないようにすることをお勧めします。同じユーザーで LoginUser を RemoveUser と同時に実行する場合、おそらくそれらを順次シリアル化して実行する必要があります。

于 2012-10-08T19:46:26.413 に答える
1

TBB ライブラリの特定の機能についてはわかりませんが、一般的には、SharedObjectAccessor オブジェクトを使用してのみアクセスできるロック オブジェクト (読み取り/書き込みミューテックスなど) と共にインスタンスSharedObject<Player>を公開するクラスのようなものを構築できます。Playerロックを適切に適用することを扱います。

template<typename T>
class SharedObjectAccessor;

template<typename T>
class SharedObject
{
public:
    SharedObject(const T& initial = T())
    : managedObject(initial)
    {}

private:
    friend class SharedObjectAccessor<T>;

    const T& read() const { return managedObject; }
    T& write() { return managedObject; }
    ReadWriteMutex lock;
    T managedObject;
};

template<typename T>
class SharedObjectAccessor
{
public:
    SharedObjectAccessor(SharedObject<T>& ref)
    : sharedObject(ref)
    {}

    ~SharedObjectAccessor() { sharedObject.lock.unlock(); }

    const T& get() const
    {
        sharedObject.lock.lock_read();
        return sharedObject.read();
    }

    T& set()
    {
        sharedObject.lock.lock_write();
        return sharedObject.write();
    }

private:
    mutable SharedObject<T>& sharedObject;
};
于 2012-10-08T20:02:45.953 に答える