WaitAll для нескольких дескрипторов в потоке STA не поддерживается - PullRequest
42 голосов
/ 16 ноября 2010
  1. Почему я получаю это сообщение об ошибке? «WaitAll для нескольких дескрипторов в потоке STA не поддерживается.»
  2. Должен ли я использовать атрибут [MTAThreadAttribute]? Обновление: Не работает с приложениями WPF!

Примечание: Это ошибка в строке WaitHandle.WaitAll (doneEvents); Я использую стандартный 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!");
}

Обновление: Следующее решение не работает для приложений WPF! Невозможно изменить основной атрибут приложения на MTAThreadAttribute. Это приведет к следующей ошибке:

Ошибка:"WaitAll для нескольких дескрипторов в потоке STA не поддерживается."

Ответы [ 5 ]

49 голосов
/ 07 апреля 2011

На самом деле я использую следующее, чтобы заменить WaitHandle.WaitAll (doneEvents);

foreach (var e in doneEvents)
    e.WaitOne();
18 голосов
/ 16 ноября 2010

Как насчет использования Задач, чтобы сделать ваши потоки для вас.

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);
10 голосов
/ 16 ноября 2010

Используйте один ManualResetEvent и ждите его.Также сохраняйте переменную TaskCount, для которой задано количество запускаемых рабочих потоков, используйте Interlocked.Decrement в коде рабочего потока в качестве самого последнего действия рабочего и сигнализируйте событие, если счетчик достигает нуля, например,

* 1004.*
7 голосов
/ 16 ноября 2010

Я бы реорганизовал ваш код для использования класса 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 голосов
/ 16 января 2012

используйте что-то вроде этого:

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