不支持STA线程上的多个句柄的WaitAll

时间:2010-11-16 09:50:30

标签: c# multithreading threadpool

  1. 为什么会收到此错误消息? “不支持在STA线程上使用多个句柄的WaitAll。”
  2. 我应该使用[MTAThreadAttribute] attribut吗? 更新:无法使用WPF应用程序!
  3. 注意:  它的错误是在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。这将导致以下错误:

    错误:“不支持在STA线程上使用多个句柄的WaitAll。”

5 个答案:

答案 0 :(得分:49)

实际上我使用以下内容替换WaitHandle.WaitAll(doneEvents);

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

答案 1 :(得分:18)

如何使用“任务”为您执行线程处理。

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 :(得分:10)

使用一个ManualResetEvent并等待它。还要维护一个TaskCount变量,该变量设置为您启动的工作线程数,在工作线程代码中使用Interlocked.Decrement作为工作人员的最后一个操作,并在计数器达到零时发出事件信号,例如

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

答案 3 :(得分:7)

我会重构您的代码以改为使用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!"); 
} 

答案 4 :(得分:0)

使用类似的东西:

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