3
class Manager {
public:

    list<Employee> getEmployees() {
        // Do I need to lock here?
        return emps_;
    }
    void addEmp(Employee emp); //Here I have lock
private:
    list<Employee> emps_;
};

インスタンスManagerは複数のスレッド間で共有されます。getEmployeesメンバー関数にロックを追加する必要がありますか?

完全なリストがコピーされるので、ロックが必要だと確信しています。そのため、その間に(コピーが完了するまで)行われる変更は、コピー操作を中断する可能性があります。

ロックする必要がないという意見がほとんどなかったので、私はこれを尋ねています。

編集

ロックする必要があることが明らかになったので、私の質問は、最小限のオーバーヘッドでこれを行う方法です。以下の解決策を実行することにより、リストを2回コピーします。

list<Employee> getEmployees() {
    pthread_mutex_lock( &mutex1 );
    list<Emp> tmp  = emps_; //Copy 1 
    pthread_mutex_unlock( &mutex1 );
    return tmp;//Copy 2
}
4

2 に答える 2

12

リスト全体がコピーされますが、コピーのソースが変更されている可能性があります。stdlibコンテナは、完全同時のロック解除された読み取りアクセスをサポートします。一方、書き込み...

コピーが作成される可能性があるときにこのリストに書き込む場合は、リストをロックする必要があります。SWMR(Single Writer Multi Reader)ロックは、これに最適です。特に、コピーを作成する必要のあるスレッドが数十または数百あり、たまにしか書き込みが必要ない場合はなおさらです。それでも、ライター要求の飢餓は、ロッキングクラスの実装によって対処される本当の懸念事項ですが、ここでの質問の範囲ではありません(しゃれは意図されていません)。

あなたのアップデートに関して、私はスコープが適切なときにリリースされたロックの大ファンです、そしてあなたの場合はそうです。つまり、ミューテックスのスコープオブジェクトラッパーは、エントリ時にラッチし、スコープ出口でラッチを解除します。

私はブーストを確信しています::みんなはそのようなものに簡単にアクセスできます、そしてそれに関してはC ++ 11もそうかもしれません(私は仕事のスケジュールのためにまだその急落をしていません;ダウンタイムはありません)。しかし、あなたはこのようなものが欲しいです:

list<Employee> getEmployees() 
{
    scope_lock latch(&mtx);
    return emps_;
}

上記scope_lockは、構築時にミューテックスをラッチし、破棄時にラッチを解除する単純なクラスです。これにより、コピー構築でスローされた例外がミューテックスを永続的にハングさせないという非常に現実的な可能性から保護されます。ミューテックスのロックを解除するための自動破壊の悪用と考えてください。勝利のためのRAII 。

それが理にかなっていることを願っています。そのような小さなゲッターにとって、そのようなものは理想的です。繰り返しになりますが、ブーストを含む多くのツールキットにはそのようなものが組み込まれている可能性があります。ブーストの人がこれを読んだ場合は、カウボーイアップしてポインターを貸してください。上記の例は、あなたが得ることができるのと同じくらい簡単なスコープロックの理想です。

最後に、SWMRの場合、ロジックはまったく同じです。唯一の違いは、ロックが読み取りまたは書き込みアクセスを要求しているかどうかの追加の引数を取ることです。

于 2012-09-25T09:06:59.353 に答える
-3

あなたの場合、少なくともあなたが示したコードでは、ロックは必要ないと思います。その理由は、リスト全体がコピーされるためです。そのため、関数を呼び出す各スレッドは、リストの独自のプライベート コピーを取得します。

于 2012-09-25T09:05:10.447 に答える