web-dev-qa-db-fra.com

WaitAll pour plusieurs descripteurs sur un thread STA n'est pas pris en charge

  1. Pourquoi ai-je ce message d'erreur? "WaitAll pour plusieurs descripteurs sur un thread STA n'est pas pris en charge."
  2. Dois-je utiliser l'attribut [MTAThreadAttribute]? Mise à jour: Ne fonctionne pas avec les applications WPF!

Remarque: cette erreur se trouve à la ligne WaitHandle.WaitAll (doneEvents); J'utilise un standard 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!");
}

pdate: La solution suivante ne fonctionne pas pour les applications WPF! Il n'est pas possible de remplacer l'attribut d'application principal par MTAThreadAttribute. Cela entraînera l'erreur suivante:

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

45
Amir Rezaei

Qu'en est-il de l'utilisation des tâches pour réaliser 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);
20
Oliver

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

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

Utilisez un ManualResetEvent et attendez-le. Conservez également une variable TaskCount définie sur le nombre de threads de travail que vous démarrez, utilisez Interlocked.Decrement dans le code de thread de travail comme la 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();
11
liggett78

Je voudrais refactoriser votre code pour utiliser la classe 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!"); 
} 
7
Brian Gideon

utilisez 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);
0
CSharper