WaitAll для нескольких дескрипторов в потоке STA не поддерживается
- Почему я получаю это сообщение об ошибке? "WaitAll для нескольких ручек в потоке STA не поддерживается".
- Должен ли я использовать атрибут [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 не поддерживается."
Ответы
Ответ 1
Как насчет того, чтобы использовать задачи для вашей потоковой передачи для вас.
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);
Ответ 2
На самом деле для замены WaitHandle.WaitAll(doneEvents) используется следующее:
foreach (var e in doneEvents)
e.WaitOne();
Ответ 3
Используйте один ManualResetEvent
и ждите его. Также поддерживайте переменную TaskCount, которая настроена на число рабочих потоков, которые вы запускаете, используйте Interlocked.Decrement
в коде рабочего потока как самое последнее действие рабочего и сигнализируйте событие, если счетчик достигнет нуля, например.
// other worker actions...
if (Interlocked.Decrement(ref taskCount) == 0)
doneEvent.Set();
Ответ 4
Я бы реорганизовал ваш код для использования класса 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!");
}
Ответ 5
используйте что-то вроде этого:
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);