45 votes

WaitAll pour des handles multiples sur un thread STA n'est pas supporté

  1. Pourquoi est-ce que je reçois ce message d'erreur ? "WaitAll pour des handles multiples sur un thread STA n'est pas supporté".
  2. Dois-je utiliser l'attribut [MTAThreadAttribute] ? Mise à jour : Ne fonctionne pas avec les applications WPF !

Note : L'erreur se situe à la ligne WaitHandle.WaitAll(doneEvents) ; J'utilise un Projet WPF .

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 changer l'attribut principal de l'application en MTAThreadAttribute. Cela entraînera l'erreur suivante :

Erreur : "WaitAll pour des handles multiples sur un thread STA n'est pas supporté".

52voto

Calimero100582 Points 417

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

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

20voto

Oliver Points 2004

Pourquoi ne pas utiliser les Tâches pour faire le filetage à votre place ?

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);

10voto

liggett78 Points 8268

Utilisez un ManualResetEvent et l'attendre. Maintenez également une variable TaskCount qui est définie sur le nombre de fils de travail que vous démarrez, utilisez Interlocked.Decrement dans le code du fil d'exécution du travailleur comme toute dernière action du travailleur et signaler l'événement si le compteur atteint zéro, par exemple

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

7voto

Brian Gideon Points 26683

Je remanierais votre code pour qu'il utilise l'option CountdownEvent à la place.

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!"); 
}

0voto

CSharper Points 3177

Utilisez quelque chose comme ça :

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);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X