2009-08-13 4 views
-2

Ich habe eine Liste von Themen, und ich versuche, meinen Haupt-Thread zu bekommen für alle Threads in der Liste warten zu beenden:Gibt es eine Möglichkeit, die Existenz von Listenelementen und Aufrufmethoden für Listenelemente automatisch zu überprüfen?

while (consumers.Count > 0) consumers[0].Join(); 

Das Problem ist, das ist nicht atomar ist, und Ich kann eine Ausnahme "Index war außerhalb des zulässigen Bereichs" erhalten.

Gibt es einen atomaren Weg, um die Existenz von Verbrauchern [0] zu überprüfen und Verbraucher [0] .Join() anzurufen?

Hinweis: Ich kann nicht

lock (myLocker) { if (consumers.Count > 0) consumers[0].Join(); } 

tun, weil ich will nicht den Zugriff auf Verbraucher die anderen Threads blockieren, während stecken in Join().

Antwort

5

Nun, wenn Sie haben noch keine Synchronisation bei allen angewendet, sondern Ihre Liste wird von mehreren Threads geändert, Sie sind bereits in Schwierigkeiten. Verwendet alles andere myLocker? Unter der Annahme, es tut, wie etwa:

while(true) 
{ 
    List<Thread> copy; 
    lock (myLocker) 
    { 
     copy = new List<Thread>(consumers); 
    } 
    if (copy.Count == 0) 
    { 
     break; 
    } 
    foreach (Thread thread in copy) 
    { 
     thread.Join(); 
    } 
} 

Beachten Sie, dass diese nurconsumers zugreift, während die Sperre hält, das ist, was Sie sollten überall tun Thread-Sicherheit zu erreichen. Es ruft auch Join auf alle die Threads nach dem Erstellen einer Kopie, anstatt nur eine für jede Iteration zu tun.

Wenn Sie wissen, dass Threads an dieser Stelle nicht in die Liste aufgenommen werden (zB es ist ein Thread-Pool, das ist Trockenlegung) die Schleife entfernen und die Kontrolle:

List<Thread> copy; 
    lock (myLocker) 
    { 
     copy = new List<Thread>(consumers); 
    } 
    foreach (Thread thread in copy) 
    { 
     thread.Join(); 
    } 
+0

Außer meiner Kopie wäre sofort abgestanden. Ich stelle mir thread.Join() würde fehlschlagen, wenn der Thread bereits beendet wurde? – mbeckish

+0

Alle anderen Zugriffe auf die Verbraucher sind synchronisiert. Lassen Sie es mich wissen, wenn Sie einen anderen Code sehen würden. – mbeckish

+2

@mbeckish: Ihre Kopie wird immer * sofort * abgestanden sein, sobald Sie darauf zugegriffen haben - und Ihre Intuition über Thread.Join ist falsch, wie dokumentiert: "Wenn der Thread bereits beendet wurde, wenn Join aufgerufen wird, kehrt die Methode sofort zurück." Vorausgesetzt, dass Sie nicht atomar "Thread-Status überprüfen und Join verbinden" können, wird jede Join-API, die eine Ausnahme auslöst, wenn der Thread bereits beendet wurde, vom Entwurf getrennt. –

0

Unter der Annahme, Verbraucher [0] wird nur null oder eine Instanz der Klasse mit der erwarteten Methode, könnten Sie gerade tun

while (consumers.Count > 0) 
    { 
    if (consumers[0] != null) 
     { 
     consumers[0].Join(); 
     } 
    } 
+0

Der Punkt ist, dass die Liste * leer geworden ist, nachdem die Zählung überprüft wurde *. –

0

In Ihrem Szenario, Wenn Sie nur auf Threads warten möchten, warum sollten Sie davon ausgehen, dass diese Threads selbst aus der Liste entfernt werden sollten? Stellen Sie sicher, dass nur der Haupt-Thread einen Thread aus der Liste entfernen kann, nachdem dieser Thread beendet wurde, wird Ihr Design nicht geändert und Sie können sicher sein, dass Sie nicht auf das Element zugreifen werden, das nicht dort ist. Ihre Schleife würde so aussehen:


for (int i = 0; i < consumers.Count; ++i) 
    consumers[i].Join(); 
//Now that you have joined everyone, just remove reference to your list 
consumers = null; 
Verwandte Themen