2016-11-24 21 views
0

私の理解には、彼らはしません。ご確認ください。Do lockはリスト要素のスレッド安全を保証しますか?

リストを含むProcessorオブジェクトがあるとします。<T>ここで、Tは参照型です。

UIスレッドはProcessorオブジェクトをインスタンス化し、周期的に呼び出してリストを取得します<T>。

プロセッサオブジェクトは、作成時にリスト<T>への参照を持つタスクも開始します。

ロックは、彼らがリスト<T>への排他的アクセスを確保するためにゲッターで、タスクにT >リスト<へのアクセスを確保するために使用されます。

public class Processor 
{ 
    private List<T> _list = new List<T>(); 
    private Object _listLock = new Object(); 

    public Processor() 
    { 
    // populate _list 

    Task t = new Task(Process); 

    t.Start(); 
    } 

    public List<T> GetList() 
    { 
    lock(_listLock) 
    { 
     return _list; 
    } 
    } 

    private void Process() 
    { 
    while(!doneProcessing) 
    { 
     lock(_listLock) 
     { 
     // access and modify _list items 
     } 

     Thread.Sleep(...); 
    } 
    } 
} 

しかし、リスト<T>はゲッターにロックされ、そしてそれがロックを捕捉するとき、プロセッサによって開始されたタスクがまだ参照型リスト要素を変更している、問題なくリストの参照が返されても。

リストの要素はプロセッサのタスクから変わる可能性があり、UIスレッドでアクセスするとスレッドセーフではありません。

私が正しいとすれば、明白な解決策は、ゲッターにリスト要素のディープコピーが移入された新しいリストを返すようにすることです。

public List<T> GetList() 
{ 
    lock(_listLock) 
    { 
    return _list.Select(t => t.Clone()).ToList(); 
    } 
} 

他に何ができますか?

+0

答えはありませんが、 'ToList()'を呼び出すだけでリストのコピーが作成されます。 – stuartd

+0

リスト全体ではなく、使用している 'List 'からメソッドだけを公開することができます。そうすれば、アイテムのアクセスと変更にロックを使用することができます。 –

+0

リストの要素を変更する際に、このようなリストのロックがトレッドセーフティを提供しないという事実を明確にしていますか? – Enigmativity

答えて

0

あなたのGetListのは()あなたはそれがないと思う何をしていません。

public List<T> GetList() 
    { 
    lock(_listLock) 
    { 
     return _list; 
    } 
    } 

GetListのので、()だけでロック、_listへの参照を返します()参照を取得から2つのスレッドを防ぐ除いて何もしませんとにかく問題にはならない、同時に_listすること。

リストオブジェクトへの参照をUIスレッドに戻していて、UIスレッドが要素を反復している間に、参照によって指されるリスト内の要素がいつでも変更されるという問題があります、それは良くありません。

ロックオブジェクトをUIスレッドに公開することができますが、これはリストが更新されている間にUIをブロックする必要があることを意味します。通常は望ましくありません。

あなたのUIがリストをどのように処理するかによって、あなたのリストの不変なスナップショットを取得し、それをUIに戻す方が良いかもしれません。

基本となるリストデータの変更に合わせてUIを維持したい場合、実際に取るアプローチはUIテクノロジに依存します。

2

あなたが持っていた方法でロックされたロックは、スレッドの安全性を保証しません。

スレッドセーフである場合は、.NET CLRのthread safe collectionsのいずれかを使用することを検討してください。

スレッドセーフなIListはありません。 Here's why。スレッドセーフリストのまさにその考えはあまり意味がありません。しかし、若干の設計変更により、ConcurrentDictionaryまたはConcurrentBagのようなものを簡単に使用できます。

関連する問題