2010-11-16 28 views
38
  1. Pourquoi j'obtiens ce message d'erreur? "WaitAll pour plusieurs handles sur un thread STA n'est pas pris en charge."
  2. Devrais-je utiliser l'attribut [MTAThreadAttribute]? Mise à jour: Ne fonctionne pas avec les applications WPF!

Remarque: Cette erreur se situe à la ligne WaitHandle.WaitAll (doneEvents); J'utilise un projet WPF standard.WaitAll pour plusieurs handles sur un thread STA n'est pas pris en charge

private void Search() 
{ 
    const int CPUs = 2; 
    var doneEvents = new ManualResetEvent[CPUs]; 

    // Configure and launch threads using ThreadPool: 
    for (int i = 0; i < CPUs; i++) 
    { 
     doneEvents[i] = new ManualResetEvent(false); 
     var f = new Indexer(Paths[i], doneEvents[i]); 
     ThreadPool.QueueUserWorkItem(f.WaitCallBack, i); 
    } 

    // Wait for all threads in pool 
    WaitHandle.WaitAll(doneEvents); 
    Debug.WriteLine("Search completed!"); 
} 

Mise à jour: La solution suivante ne fonctionne pas pour les applications WPF! Il n'est pas possible de modifier l'attribut de l'application principale en MTAThreadAttribute. Il se traduira par l'erreur suivante:

Erreur: "WaitAll pour plusieurs handles sur un thread STA n'est pas pris en charge."

+0

Vous vous rendez compte que vous geler complètement l'application jusqu'à ce que ces indexeurs sont faites? – liggett78

+0

Oui! Je le sais. Mais comme c'est il ne fonctionne pas. –

+1

http://stackoverflow.com/questions/3784510/notsupportedexception-on-waithandle-waitall –

Répondre

17

Qu'en est-il de l'utilisation des tâches pour faire votre threading pour vous.

http://msdn.microsoft.com/en-us/library/system.threading.tasks.task.aspx

var task1 = Task.Factory.StartNew(() => DoSomeWork()); 
var task2 = Task.Factory.StartNew(() => DoSomeWork()); 
var task3 = Task.Factory.StartNew(() => DoSomeWork()); 
Task.WaitAll(task1, task2, task3); 
+4

C'est .NET Framework 4. Je dois donc mettre à jour le projet. Cela semble être une meilleure approche pensée! –

+2

'Task.Run (() => DoSomeWork())' est une meilleure alternative – gldraphael

8

Utilisez un ManualResetEvent et patientez. Maintenez également une variable TaskCount qui est définie sur le nombre de threads de travail que vous démarrez, utilisez Interlocked.Decrement dans le code de thread de travail en tant que toute dernière action du worker et signalez l'événement si le compteur atteint zéro, par exemple.

// other worker actions... 
if (Interlocked.Decrement(ref taskCount) == 0) 
    doneEvent.Set(); 
+0

Merci, il semble être la seule solution depuis WaitAll (..) ne fonctionne pas. –

+0

Oui, ça marcherait. Assurez-vous simplement de traiter le thread principal comme s'il s'agissait d'un élément de travail et d'initialiser 'taskCount = 1' et de faire les' Decrement' et 'Set' à la fin de la boucle' for'. –

6

Je factoriser votre code pour utiliser la classe à la place CountdownEvent.

private void Search() 
{ 
    const int CPUs = 2; 
    var done = new CountdownEvent(1); 

    // Configure and launch threads using ThreadPool: 
    for (int i = 0; i < CPUs; i++) 
    { 
     done.AddCount(); 
     var f = new Indexer(Paths[i], doneEvents[i]); 
     ThreadPool.QueueUserWorkItem(
      (state) => 
      { 
      try 
      { 
       f.WaitCallBack(state); 
      } 
      finally 
      { 
       done.Signal(); 
      } 
      }, i); 
    } 

    // Wait for all threads in pool 
    done.Signal(); 
    done.Wait(); 
    Debug.WriteLine("Search completed!"); 
} 
+0

NB: .NET 4 seulement –

45

En fait, j'utilise ce qui suit pour remplacer WaitHandle.WaitAll (doneEvents);

foreach (var e in doneEvents) 
    e.WaitOne(); 
+1

y a-t-il des inconvénients à utiliser cette alternative? – invertigo

+3

Je n'en ai vu aucun, mais je recommanderais d'utiliser la tâche pour le nouveau code – Calimero100582

0

utiliser quelque chose comme ceci:

foreach (ITask Task in Tasks) 
{ 
    Task.WaitHandle = CompletedEvent; 
    new Thread(Task.Run).Start(); 
} 

int TasksCount = Tasks.Count; 
for (int i = 0; i < TasksCount; i++) 
    CompletedEvent.WaitOne(); 

if (AllCompleted != null) 
    AllCompleted(this, EventArgs.Empty); 
+1

CompletedEvent est de type System.Threading.AutoResetEvent – CSharper

+0

-1 Bien que plus propre, pour moi ce n'est pas assez différent de http://stackoverflow.com/a/4194938/11635 –