【问题标题】:NotSupportedException on WaitHandle.WaitAllWaitHandle.WaitAll 上的 NotSupportedException
【发布时间】:2010-09-24 05:45:39
【问题描述】:

我正在尝试执行以下代码。该代码尝试并行下载和保存图像。我传递了要下载的图像列表。我用 C# 3.0 编写了它,并使用 .NET Framework 4(VS.NET 快速版)对其进行了编译。每次我尝试运行我的程序时,WaitAll 操作都会导致 NotSupportedException(不支持 STA 线程上的多个句柄的 WaitAllll)。我尝试删除SetMaxThreads,但这没有任何区别。

public static void SpawnThreads(List<string> imageList){
    imageList = new List<string>(imageList);
    ManualResetEvent[] doneEvents = new ManualResetEvent[imageList.Count];
    PicDownloader[] picDownloaders = new PicDownloader[imageList.Count];
    ThreadPool.SetMaxThreads(MaxThreadCount, MaxThreadCount);
    for (int i = 0; i < imageList.Count; i++) {
        doneEvents[i] = new ManualResetEvent(false);
        PicDownloader p = new PicDownloader(imageList[i], doneEvents[i]);
        picDownloaders[i] = p;
        ThreadPool.QueueUserWorkItem(p.DoAction);
    }
    // The following line is resulting in "NotSupportedException"     
    WaitHandle.WaitAll(doneEvents);
    Console.WriteLine("All pics downloaded");
}

你能告诉我我遇到了什么问题吗?

谢谢

【问题讨论】:

    标签: c# multithreading threadpool


    【解决方案1】:

    我建议不要使用多个 WaitHandle 实例来等待完成。请改用CountdownEvent 类。它会产生更优雅和可扩展的代码。另外,WaitHandle.WaitAll 方法最多只支持 64 个句柄,并且不能在 STA 线程上调用。通过重构您的代码以使用我想出的规范模式。

    public static void SpawnThreads(List<string> imageList)
    { 
      imageList = new List<string>(imageList); 
      var finished = new CountdownEvent(1);
      var picDownloaders = new PicDownloader[imageList.Count]; 
      ThreadPool.SetMaxThreads(MaxThreadCount, MaxThreadCount); 
      for (int i = 0; i < imageList.Count; i++) 
      { 
        finished.AddCount();    
        PicDownloader p = new PicDownloader(imageList[i]); 
        picDownloaders[i] = p; 
        ThreadPool.QueueUserWorkItem(
          (state) =>
          {
            try
            {
              p.DoAction
            }
            finally
            {
              finished.Signal();
            }
          });
      } 
      finished.Signal();
      finished.Wait();
      Console.WriteLine("All pics downloaded"); 
    } 
    

    【讨论】:

    • 谢谢布赖恩。会试试看。
    【解决方案2】:

    您是否使用[STAThread] 属性标记了其中一种方法?

    【讨论】:

    • 谢谢丹尼!主应用程序线程确实被标记为 [STAThread]。我删除了它并像魔术一样工作。为什么VS.NET默认所有的入口方法都是[STAThread]?
    • @Ravi:我不认为这个属性会被默认标记为main。也许是你自己标记的?
    • 我知道这有点老了,但是在 VS2012 Express for Desktop 中——我从头开始创建了一个全新的应用程序,实际上在 Program.cs 文件中,Main 用 STAThread 属性装饰。我删除了它,现在它对我有用。谢谢大家!
    【解决方案3】:

    您是否尝试过为线程设置单元状态?

    thread.SetApartmentState (System.Threading.Apartmentstate.MTA );
    

    【讨论】:

    • 谢谢,但我只是创建一个线程池,而不是单个线程! ThreadPool 不允许我设置 ApartmentState。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-11
    相关资源
    最近更新 更多