2012-04-10 5 views
1

Angenommen, ich habe eine Liste in einer Klasse, die in einem Multithreading-Szenario verwendet wird.Auflisten einer Liste in einer thread-sicheren Weise

public class MyClass 
{ 
    List<MyItem> _list= new List<MyItem>(); 
    protected object SyncRoot { 
     get { 
     return ((IList)_list).SyncRoot; 
     } 
    } 

    public void Execute1() 
    { 
     lock(SyncRoot) 
     { 
      foreach(var item in _list) DoSomething(item); 
     } 
    } 

    public void Execute2() 
    { 
     Item[] list; 
     lock(SyncRoot) 
     { 
      list=_list.ToArray(); 
     } 
      for(var i=0;i<list.Length;i++) DoSomething(list[i]); 
     } 
} 

Verfahren EXECUTE1 ist die 'normale' Weg, um die Liste in eine Thread-sichere Weise aufzuzählen. Aber was ist mit Execute2? Ist dieser Ansatz noch Thread-sicher?

+1

Nein, Execute2 ist nicht sicher, wenn MyItems Referenztypen (Objekte) sind, da die Liste und das Array letztendlich auf dieselben Objekte verweisen. – Will

+0

@Will Das ist in diesem speziellen Szenario kein Problem, da ich mich nur um die Liste selbst kümmere. Die Objekte können sich selbst synchronisieren, wenn dies erforderlich ist. – MikeSW

+0

@HenkHolterman Ich weiß, dass ich jedes Objekt verwenden kann, aber ich frage mich, ob es besser ist, das Sync-Objekt der Liste zu verwenden. Ich meine, deshalb ist es ausgesetzt, nein ?! – MikeSW

Antwort

1

Es ist sicher, solange jede andere Verwendung von _list auch mit der gleichen lock Anweisung geschützt ist. Sie nehmen exklusiven Zugriff auf die Liste, kopieren ihren Inhalt und arbeiten dann an der Kopie (auf die Sie aufgrund des Bereichs auch exklusiv Zugriff haben). Auf den ersten Blick etwas verschwenderisch, unter bestimmten Umständen aber auch legitim.

+0

Ja, fügen Sie hinzu/entfernen Sie Elemente aus der Liste sind mit der gleichen Sperre gemacht. Allerdings verstehe ich nicht recht, warum die lokale Liste automatisch exklusiven Zugriff erhält. – MikeSW

+0

@MikeSW: Weil es für alle anderen außerhalb des Geltungsbereichs außer der Methode 'Execute2' ist. – Jon

2

Der Zugriff auf die (Kopie der) Liste ist threadsafe in beiden Szenarien. Aber natürlich sind die MyItem-Elemente in keiner Weise synchronisiert.

Das zweite Formular sieht ein wenig teurer aus, aber es wird Hinzufügen/Entfernen auf dem Original zulassen, während die DoSomething() s ausgeführt werden. Das Array verhält sich wie eine Art Momentaufnahme, wenn es Ihren Anforderungen entspricht, könnte es nützlich sein. Beachten Sie, dass Sie auch ToList() verwenden können.

Verwandte Themen