2011-12-02 13 views
3

は、私は、次のC#のコードを持っている:ロック/同時実行の問題

1. List<BandEdge> bandEdgeList; 
2.  
3. bandEdgeList = CicApplication.BandEdgeCache.Where(row => row.Coater == coater).ToList(); 
4. foreach (BandEdge bandEdge in bandEdgeList) 
5.  { 
6.   ... 
7.   ... 
8.  } 

私の質問はこれです。 3行目に 'bandEdgeList'が設定されると、別のスレッドがCicApplication.BandEdgeCacheの内容を変更した場合、 'bandEdgeList'の内容は無効になりますか?私はCicApplication.BandEdgeCacheゲッター/セッターにロックを持っています。しかし、私は 'bandEdgeList'で作業している間にCicApplication.BandEdgeCacheの内容が変更されないように、このコードブロックの周りにロックを置くべきかどうかと思います。

+0

もし 'BandEdgeCache'も編集可能なコレクションであれば、あなたのローカルリストの項目が欠けている可能性があります。あなたの' Coater'条件を満たしていない項目があるかもしれません。以下の答えにある問題に加えて、 'BandEdgeCache'コレクションがあります。 – Marc

答えて

5

自動的には発生しませんが、スレッドセーフではありません。それはInvalidOperationExceptionを投げることができます。

ToListが呼び出されると、その参照のコピーが保存されます。しかし、それが起こっている間に別のスレッドがBandEdgeCacheを変更すると、悪いことが起こります。

したがって、すべての参照をBandEdgeCacheにロックする必要があります。

しかし、保存されたリストの行によれば、それは安全ですが、BandEdgeを変更するとロックがなくてもスレッドセーフではありません。

3

bandEdgeListは、(ToList()を使用しているため)独立したコピーになるため、ロックする必要はありません。

@Daniel A. Whiteがコメントしたように、そのコピーを作成するLINQ文をロックする必要があります。

+1

それは独立したコピーですが、それを作るために、 'BandEdgeCache'をロックする必要があります。 –

+0

私は今日何かを学んだ...私はToListが実際にコピーを作っていないと思ったし、あなたはToArrayを使ってコピーしなければならなかった。 –

+1

@jsobo - 参照のみをコピーします。 –

1

CicApplication.BandEdgeCacheのゲッターにロックを設定しても、コレクションへの参照が返される場合は役に立ちません。

CicApplication.BandEdgeCache{ 
    get{lock(_myCollection){return _myCollection;}} 
} 

は参照を返しますが、それはそうロック外で行われたゲッターによって返されたコレクションへの参照の場合は()関数を使用して返し、スレッドセーフではないされたらロックを終了しました。別のスレッドではコレクションを変更することができますが、ロックが保持されていない場合はWhereが反復処理されます.Danielが正しい場合、リストを生成している間に別のスレッドがコレクションを変更するとInvalidOperationExceptionがスローされます。

リストが生成されると、元のコレクションは新しいリストへのアクセスを損なうことなく変更できます。

関連する問題