4

リストがあるとします。

class CLIENTS
{
public:

    CLIENTS();
    ~CLIENTS();

    bool addClient();
    bool removeClient();
    bool getDataFromClientObj(unsigned int id);
    bool storeDataInClientObj(unsigned int id);
private:

    // vector, that contains all the clients
    boost::ptr_vector<CLIENTOBJ> clients;

    // mutex for the client-list
    boost::mutex mutex;
};

さらに、getDataFromClientObj() が共有ロック (ミューテックス、プライベート) を取得することを検討してください。それに加えて、getDataFromClient() を介してクライアントからデータを取得できるようにする必要があります。

クライアントのキューにデータがまったくない場合、 getDataFromClient() は、新しいデータを読み取るまで、そのクライアントの条件変数を待機します。

さて、ここに私の問題があります:
getDataFromClient(); getDataFromClient() がミューテックス ロックを保持しているため、新しいクライアントを追加したり、クライアントを削除したりできません。

リストがある場合、シナリオを正確にどのように解決しますか?

ここでもう一度、事実を示します。

  • スレッドセーフ リスト (複数のリーダー / 単一のライター)
  • いつでもクライアントを追加/削除できること
  • 具体的には、各クライアントの (特定の) 条件で待機できること (あるクライアントは新しいデータを自分のキューに格納し、別のクライアントは格納していない可能性があります。その場合、 getDataFromClient() は、新しいデータが読み込まれるまで待機します)

私が思う問題は、クライアントごとに 1 つの条件がある場合 (疑似コード: if(clientsqueue.isEmpty() -> wait)、複数の条件変数が必要であるということです (私は間違っていますか?)

詳細情報:
OS: Windows 7
言語: C++
コンパイラ VS2010

4

1 に答える 1

1

あなたの設定は非常にDBishです。Clientsクラスによって表されるテーブルと、主キーとして機能CLIENTOBJするテーブルの行のように機能するそれぞれのいくつかのインスタンスがあります。idただし、私が理解していることから、各クライアントは実際にはデータ キューです。

データベースで使用されるモデルは、データへのアクセスをデータベース内の専用アクティビティ (スレッドまたはプロセス) に委譲し、SQL を使用してコマンドを送信するものとして大まかに説明できます。同期の問題は、トランザクションと SQL 句で処理されます (シークが存在しない場合、更新は行にまったく影響を与えない可能性がありますidが、そのコマンドは失敗せず、更新された 0 行が返されるだけです)。あなたのケースでは、おそらく同様のモデルが興味深いでしょう。トランザクションを表す 1 つのグローバル ミューテックスだけで、各スレッドがデータ構造全体をロックし、操作し、ロックを解除します。ただし、これはあまり効率的ではない可能性があります。

非同期に相当するのは、各コマンドstd::futureが実際の結果ではなく を返すようにすることです。それ以降、スレッドは を待機するだけでよく、future完了した (または例外で中断された) ときに処理を実行します。

インスタンス内では、すべてのメソッド呼び出しがおよび にClients変換されます。promise は promise キューにプッシュされ、呼び出し元のスレッドはメソッド呼び出しから future を取得するか、すぐにそれを待機します。futurepromise

DB プロセスの観点から見ると、これはシーケンシャルな作業です。他のすべてのスレッドが、送信先のクライアント ID にバンドルされたデータをプッシュする 1 つの promise キューがあります。次に、結果の promise が DB スレッドによって次の順序で満たされます。

  • 新しいクライアントを作成する
  • クライアントを削除する
  • ストアの場合、DB スレッドは保留中の読み取りがあるかどうかを確認し、それを満たすか、単にそのデータをクライアント キューに入れます。
  • 読み取りでデータがある場合は、それをクライアント キューからプルしてスレッドに渡すか、クライアントの保留中の読み取りキューにプッシュして、後でデータが使用可能になったときに満たされるようにします。

上記のソリューションでは、すべての依存関係が分離され、タスクが合理化されます。

また、 ごとに 1 つのスレッドを専用にすることもできますCLIENTOBJ。次に、DB スレッドはトリアージ スレッドになり、Promise を各クライアントに配布するだけです。各クライアントは、特定の の保留中の読み取りおよびデータ キューを所有するidため、promise の処理に関連するロックはありません。

各キューはミューテックスで保護する必要があります。これは、メインの promise キューに 1 つのミューテックス、各クライアントの promise キューに 1 つのミューテックス、およびClientsメソッドを使用するスレッドと同じ数の条件変数を意味します。

アップデート:

私の答えは最初に次のことを提案しました:

つまり、future/promise メカニズムを、各非 DB スレッドに関連付けられた単純な条件変数に置き換えることができます (future と promise はおそらく cond. 変数を使用して実装されますが、ここでは作成と破棄のオーバーヘッドを節約できます)。

CLIENTSただし、オブジェクトの使用方法に対していくつかの暗黙の仮定を行います。最も安全な道は確かにstd::future1 つです。

于 2013-03-20T19:50:25.523 に答える