2012-12-26 11 views
5

Wątek jest gotowy do utworzenia 4 oddzielnych wątków i czekać na każdy z nich, aż do końca. Każdy wątek jest uśpiony i kończy się tylko wtedy, gdy wspólny obiekt Mutex nie jest zajęty przez inny wątek, a następnie sygnalizuje zakończenie zdarzenia (Jest to uproszczona wersja mojego kodu, ale kończy się niepowodzeniem w tym samym miejscu). co się dzieje, jest to, że przez większość czasu wątek główny będzie czekał wiecznie na jednym z WaitOne() pozornie losowo.WaitOne() czeka na zawsze, mimo że wszystkie zdarzenia rozpoczęte

Również musiałem skomentować out niektóre części mojego kodu, bo to doprowadziło do jeszcze bardziej nieoczekiwane zachowanie (czyli jakoś po każdy wątek zakończeniu głównego wątku byłoby przeskoczyć z powrotem do klauzuli FOR i spowodować 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(); 
    } 
} 

Każda pomoc będzie wielki

+0

Czy tworzenie więcej niż jednego z tych obiektów? Statyczne elementy wydają się niebezpieczne dla obiektu nie będącego singletonem. –

+0

Rozważ użycie [Zadania] (http://msdn.microsoft.com/en-us/library/dd270695 (v = vs.100) .aspx) w celu oczyszczenia tej logiki. – roken

+0

@roken: Myślę, że Tasks nie oczyści przepływu, który jest obecny, jest tylko inną konstrukcją do pracy asynchronicznej z większą ilością enatowych pomocników/rozszerzeń. – sll

Odpowiedz

7

najprawdopodobniej wszystkie cztery wątki wykona:

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

ma to zrobić z wykorzystaniem closu res. Wszystkie cztery wątki będą powiązane ze zmienną i i będą używać dowolnej wartości, jaką ma po wykonaniu kodu (a nie wartości, gdy zostanie utworzony obiekt Thread).

Twój kod prawdopodobnie nie zadziała, jeśli wszystkie cztery wątki używają tej samej wartości.

+0

Sprawdź także ten post http://stackoverflow.com/questions/271440/c-sharp-captured-variable-in-loop – sll

+0

Będę przeklęty. To była ostatnia rzecz, którą uważałem za przyczynę. Ale dlaczego wątki wykonują się z bieżącym i, a nie tym, który przeszli przez parametry? // edycja właśnie zobaczyła link po opublikowaniu – user1927074

+0

W "StartIndexCrawling" masz lokalną kopię wartości. Ale najwyższym kodem wątku jest anonimowa funkcja zdefiniowana przez zamknięcie '() => this.StartIndexCrawling (1, i, i + 1, evs [i])'. A ten kod odnosi się do wspólnej zmiennej "i". Tak działają zamknięcia. – Codo

0

Zobacz odpowiedź Codo.
Oto co należy zrobić, aby rozwiązać go:

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(); 
Powiązane problemy