3

このアプリケーションでは、ワーカー スレッドで処理され、表示スレッドでアクセスされるデータを処理し、クリティカル セクションを処理するミューテックスを使用しています。特にない。

ここで、データを保持および処理する当事者によって現在ロックが明示的に行われているコードを作り直すことを考えました。データを保持し、保護された方法でのみデータへのアクセスを許可する単一のエンティティを考えました。

このために、GuardedData というクラスがあります。呼び出し元はそのようなオブジェクトを要求でき、ローカル スコープで短時間だけ保持する必要があります。オブジェクトが生きている限り、ロックを保持します。オブジェクトが破棄されるとすぐに、ロックが解除されます。データ アクセスは、呼び出し元での明示的な追加作業なしで、ロック メカニズムと結合されます。クラスの名前は、呼び出し元に現在のガードを思い出させます。

template<typename T, typename Lockable>
class GuardedData {
    GuardedData(T &d, Lockable &m) : data(d), guard(m) {}
    boost::lock_guard<Lockable> guard;
    T &data;

    T &operator->() { return data; }
};

繰り返しますが、非常に単純な概念です。operator-> は、ペイロードにアクセスするための STL イテレータのセマンティクスを模倣します。

今、私は疑問に思います:

  • このアプローチはよく知られていますか?
  • このようなテンプレート化されたクラスは、ブースト ライブラリなどで既に利用可能ですか?

それはかなり一般的で使用可能な概念だと思うので、私は尋ねています。私はそれのようなものを見つけることができませんでした。

4

2 に答える 2

2

これがどのように使用されるかに応じて、ある時点でデッドロックが発生することがほぼ保証されます。2 つのデータを操作したい場合は、mutex を 2 回ロックしてデッドロックすることになります (データの各部分に独自のミューテックスがある場合を除きます。ロックの順序が一貫していない場合もデッドロックが発生します。制御することはできません)。本当に複雑にすることなく、このスキームでそれを行います)。望ましくないかもしれない再帰ミューテックスを使用しない限り。

また、GuardedData オブジェクトはどのように渡されますか? boost::lock_guard はコピー可能ではありません - ミューテックスの所有権の問題、つまりいつどこで解放されるかの問題が発生します。

クリティカル セクションを短くして、必要なときに必要なデータの一部をリーダー/ライター スレッドにコピーする方がおそらく簡単です。ライターも同様に、一度にデータ モデルにコミットします。

基本的に、ビューア スレッドは、特定の時点で必要なデータのスナップショットを取得します。これは、スレッドを実行しているコアの近くにある CPU キャッシュに完全に収まり、RAM に収まらない場合もあります。ライター スレッドは、リーダーが処理している間に基になるデータを変更する場合があります (ただし、ビューは無効になります)。ただし、ビューアーにはコピーがあるため、引き続きデータと同期された時点でデータのビューを提供できます。

もう 1 つのオプションは、ビューにデータへのスマート ポインターを与えることです (これは不変として扱われるべきです)。ライターがデータを変更したい場合、その時点でそれをコピーし、コピーを変更し、完了すると、ポインターをモデル内のデータに切り替えます。これにより、ライターが 1 つしかない場合を除き、処理中にすべてのリーダー/ライターをブロックする必要があります。リーダーが次にデータを要求すると、新しいコピーが取得されます。

于 2013-03-21T14:02:00.943 に答える
1

よく知られていますが、よくわかりません。ただし、QMutexLockerと呼ばれる同様のメカニズムを Qt でよく使用します。違い(マイナーなもの、私見)は、データをミューテックスと一緒にバインドすることです。あなたが説明したものと非常によく似たメカニズムが、C# でのスレッド同期の標準です。

あなたのアプローチは、一度に 1 つのデータ項目を保護するのに適していますが、それ以上の保護が必要な場合は面倒です。さらに、あなたの設計では、このオブジェクトを共有の場所に作成し、データが完全に保護されていると考えて、好きなだけデータにアクセスすることを妨げているようには見えませんが、実際には再帰的なアクセスシナリオは処理されず、処理されません。マルチスレッド アクセス シナリオが同じスコープで発生する場合。

考え方に若干のズレがあるようです。これを使用すると、データが保護されているため、データへのアクセスは常にスレッドセーフになることがわかります。多くの場合、これはスレッドセーフを確保するには不十分です。保護されたデータに対する操作の順序は重要な場合が多いため、ロックは実際にはデータ指向ではなくスコープ指向です。ダミー オブジェクトを保護し、保護オブジェクトを一時的なスコープにラップすることで、モデル内でこれを回避できますが、既存のミューテックス実装の 1 つだけを使用しないのはなぜでしょうか?

実際、これは悪いアプローチではありませんが、その使用目的を理解する必要があります。

于 2013-03-21T13:53:59.583 に答える