2012-12-26 9 views
5

Il threading viene utilizzato per creare 4 thread separati e attendere ciascuno di essi fino al termine. Ogni thread rimane inattivo per un po 'e termina solo quando il condiviso Opex di Mutex non è occupato da un altro thread e quindi segnala tramite un evento che è terminato (Questa è una versione semplificata del mio codice ma non riesce nello stesso punto)WaitOne() attende per sempre anche se tutti gli eventi sono stati attivati ​​

Ma quello che succede è che la maggior parte delle volte il thread principale aspetterà per sempre a uno dei WaitOne() apparentemente a caso.

Inoltre ho dovuto commentare-out alcune parti del mio codice fuori perché ha portato a un comportamento ancora più inaspettato (Ie in qualche modo dopo ogni thread terminato il thread principale sarebbe un salto indietro nel per la clausola e causare un IndexOutOfBounds)

class Threading 
{ 
    static Mutex CM; 
    static List<Manga> SharedList; 
    static ManualResetEvent CEvent = new ManualResetEvent(false); 
    static ManualResetEvent Event1 = new ManualResetEvent(false); 
    static ManualResetEvent Event2 = new ManualResetEvent(false); 
    static ManualResetEvent Event3 = new ManualResetEvent(false); 
    static ManualResetEvent Event4 = new ManualResetEvent(false); 

    public List<Manga> ThreadedMangaIndexCrawl(int MaxThreads) 
    { 
     CM = new Mutex(false); 
     SharedList = new List<Manga>(); 

     ManualResetEvent[] evs = new ManualResetEvent[4]; 
     evs[0] = Event1; // Event for t1 
     evs[1] = Event2; // Event for t2 
     evs[2] = Event3; // Event for t3 
     evs[3] = Event4; // Event for t4 

     /*for (int i = 0; i < MaxThreads + 1; i++) 
     { 
      if (i > MaxThreads) 
      { break; } 
      Thread t = new Thread(() => this.StartIndexCrawling(1,i,i+1,evs[i])); 
      t.Start(); 
     }*/ 
     int i = 0; 
     Thread t1 = new Thread(() => this.StartIndexCrawling(1, i, i + 1, evs[i])); 
     t1.Name = "Thread" + i; 
     t1.Start(); 
     i++; 
     Thread t2 = new Thread(() => this.StartIndexCrawling(1, i, i + 1, evs[i])); 
     t2.Name = "Thread" + i; 
     t2.Start(); 
     i++; 
     Thread t3 = new Thread(() => this.StartIndexCrawling(1, i, i + 1, evs[i])); 
     t3.Name = "Thread" + i; 
     t3.Start(); 
     i++; 
     Thread t4 = new Thread(() => this.StartIndexCrawling(1, i, i + 1, evs[i])); 
     t4.Name = "Thread" + i; 
     t4.Start(); 


     /* foreach (var e in evs) 
     { 
      e.WaitOne(); 

     }*/ 

     evs[0].WaitOne(); 
     evs[1].WaitOne(); 
     evs[2].WaitOne(); 
     evs[3].WaitOne(); 

     return SharedList; 
    } 

    void StartIndexCrawling(int Target, int Start, int End, ManualResetEvent E) 
    { 
     Thread.Sleep(1000); 
     CM.WaitOne(); 
     CM.ReleaseMutex(); 
     E.Set(); 
    } 
} 

Qualsiasi aiuto sarebbe grande

+0

Si sta creando più di uno di questi oggetti? I membri statici sembrano piuttosto pericolosi per un oggetto non singleton. –

+0

Considerare l'utilizzo di [Attività] (http://msdn.microsoft.com/en-us/library/dd270695 (v = vs.100) .aspx) per eliminare questa logica. – roken

+0

@roken: Penso che Task non ripulirà il flusso di lavoro di esecuzione che c'è, questo è solo un altro costrutto per fare il lavoro asincrono con più helper/estensioni enat – sll

risposta

7

molto probabilmente, tutte e quattro le discussioni eseguiranno:

this.StartIndexCrawling(1, 3, 3 + 1, evs[4]); 

Questo ha a che fare con l'uso di Closu res. Tutti e quattro i thread saranno associati alla variabile i e utilizzeranno il valore che ha una volta eseguito il codice (e non il valore quando viene creato l'oggetto Thread).

È improbabile che il codice funzioni se tutti e quattro i thread utilizzano lo stesso valore.

+0

Controlla anche questo post http://stackoverflow.com/questions/271440/c-sharp-captured-variable-in-loop – sll

+0

Sarò dannato. Quella fu l'ultima cosa che consideravo la causa. Ma perché i thread si eseguono con gli attuali e non colui che hanno ottenuto attraverso i parametri? // modifica ha appena visto il collegamento dopo la pubblicazione – user1927074

+0

All'interno di 'StartIndexCrawling' si ha una copia locale dei valori. Ma il codice più in alto del thread è la funzione anonima definita dalla chiusura '() => this.StartIndexCrawling (1, i, i + 1, evs [i])'. E questo codice si riferisce alla variabile condivisa 'i'. Ecco come funzionano le chiusure. – Codo

0

Vedere la risposta di Codo.
Ecco cosa si dovrebbe fare per risolverlo:

int i = 0; 
    Thread t1 = new Thread(() => this.StartIndexCrawling(1, 0, 1, Event1)); 
    t1.Name = "Thread" + i; 
    t1.Start(); 
    i++; 
    Thread t2 = new Thread(() => this.StartIndexCrawling(1, 1, 2, Event2)); 
    t2.Name = "Thread" + i; 
    t2.Start(); 
    i++; 
    Thread t3 = new Thread(() => this.StartIndexCrawling(1, 2, 3, Event3)); 
    t3.Name = "Thread" + i; 
    t3.Start(); 
    i++; 
    Thread t4 = new Thread(() => this.StartIndexCrawling(1, 3, 4, Event4)); 
    t4.Name = "Thread" + i; 
    t4.Start(); 
Problemi correlati