2009-08-20 25 views
1

Ich habe ein wenig Schwierigkeit mit der threadpool Klasse und einem Array von ManualResetEvents. Unten ist ein einfaches Beispiel für das, was ich mache. Das Problem ist, dass ich in der DoWork-Methode NULL-Referenzen auf das resetEvent [param as int] -Objekt bekomme.C# Threadpool Synchronisation Anfrage

Kann mir nicht vorstellen, was ich falsch mache.

(edit: got der Codeblock Arbeits)

private static volatile ManualResetEvent[] resetEvents = new ManualResetEvent[NumThreads]; 
public void UpdateServerData() 
{ 
    for (int i = 0; i < NumThreads ; i++) 
     { 
      resetEvents[i] = new ManualResetEvent(false); 
      ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), (object) i); 

     } 
    WaitHandle.WaitAll(resetEvents); 
} 
private void DoWork(object param) 
{ 
//do some random work 
resetEvents[(int)param].Set(); 
} 

EDIT: Ich habe versucht, eine System.Threading.Thread.MemoryBarrier Einfügen(); Nach jedem .Set() bekomme ich jedoch immer noch eine Null-Referenz-Ausnahme.

+0

Ich hatte mehrere Änderungen vorgenommen, um den Code-Block arbeiten zu lassen. Wenn jemand die früheren Iterationen gesehen hat, entschuldigen Sie die Unordnung, die es war. – Setheron

+0

Ich habe auch versucht, jeden Aufruf von .Set() zu sperren, weil das ein flüchtiges Lesen/Schreiben des Objekts verursachen sollte, das aber auch nicht zu funktionieren scheint. Sehr frustrierend. – Setheron

+0

Warum in aller Welt geben Sie eine Speicherbarriere * nach * dem 'Set()' aus? Sie müssen das aktualisierte Array-Element * sehen, bevor Sie 'Set()' darauf aufrufen! –

Antwort

0

ziemlich fand ich das Problem in

war
for (int i = 0; i < NumThreads ; i++)  
{   
resetEvents[i] = new ManualResetEvent(false);   
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), resetEvents[i]);  
} 

Anstatt eine neue Manual deklarieren ich einfach zurücksetzen() aufgerufen. Das Problem schien gewesen zu sein, dass, obwohl ich MemoryBarrier oder Sperren verwenden würde, der physische Speicher noch nicht aktualisiert würde, also würde er auf Null zeigen.

2

Sie können das Schlüsselwort as nicht verwenden, um nach int zu konvertieren (da int kein Referenztyp ist). Verwenden Sie (int)param statt:

private void DoWork(object param) 
{ 
    //do some random work 
    resetEvents[(int)param].Set(); 
} 

Ein weiterer Ansatz, ich fühle mich ist sauberer ist die Wartegriff auf das Verfahren stattdessen passieren:

public void UpdateServerData() 
{ 
    for (int i = 0; i < NumThreads ; i++) 
    { 
     resetEvents[i] = new ManualResetEvent(false); 
     ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), resetEvents[i]); 
    } 
    WaitHandle.WaitAll(resetEvents); 
} 
private void DoWork(object param) 
{ 
    //do some random work 
    (param as ManualResetEvent).Set(); 
} 

diese Weise die Arbeiter Methode über keine Kenntnis hat, wie das Warten Griff von außen verwaltet; und es kann auch nicht aus anderen Gründen Wartepunkte für andere Threads erreichen.

+0

Ich habe nur schnell ein einfaches Beispiel geschrieben. Ich wollte nicht, dass es zu 100% syntaktisch korrekt ist, aber ich werde das Beispiel beheben – Setheron

+0

dont denke, dass Sie den Parameter als Indexer verwenden wollten .... sollte (param as ManualResetEvent) .Set tun können(); – CSharpAtl

+0

@CSharpAtl: Ja, das ist mir aufgefallen. Mein Code starb der Kopie/Paste Tod, ich denke, o) –

1

volatile ManualResetEvent[] bedeutet nicht, dass der Zugriff auf Array-Elemente die volatile Semantik folgt. Nur der Zugriff auf die Variable, die den Verweis auf das Array enthält, ist flüchtig. Versuchen Sie, nach dem Zuordnen des Array-Elements eine Speicherbarriere einzufügen, oder verwenden Sie Thread.VolatileWrite, um sie zu setzen, z.

Thread.VolatileWrite (ref resetEvents[i], new ManualResetEvent (false)) ; 
+0

Oh. Ich dachte, die Zuweisung von volatile zum Array bewirkt, dass die Mitglieder das Schlüsselwort inhert. Ich bin nicht vertraut mit den anderen beiden Möglichkeiten (Speicherbarriere und Interlocked.Exchange) – Setheron

+0

Eigentlich Interlocked.Xxx ist hier keine gute Idee, da Sie Ihre Daten nicht lesen und aktualisieren müssen. –