【问题标题】:ThreadStateException when using QueueUserWorkItem in a Timer在 Timer 中使用 QueueUserWorkItem 时出现 ThreadStateException
【发布时间】:2010-06-07 14:19:19
【问题描述】:

我的 WinForms 应用程序中有一个 ThreadStateException。

重现步骤:

  • 创建简单的 winforms 应用程序
  • 添加计时器
  • 在点击事件中,做:

    timer1.Interval = 1000;
    timer1.Tick += timer1_Tick;
    timer1.Start();
    

    void timer1_Tick(object sender, EventArgs e)
    {
        ThreadPool.QueueUserWorkItem(delegate
        {
            StringCollection paths =
                new StringCollection { @"c:\my.txt", @"c:\my.png" };
            Clipboard.SetFileDropList(paths);
        });
    }
    

异常告诉我:

在进行 OLE 调用之前,必须将当前线程设置为单线程单元 (STA) 模式。确保您的 Main 函数上标记了 STAThreadAttribute。

但是main已经有了[STAThread]属性。

如何解决?

【问题讨论】:

    标签: c# winforms multithreading clipboard


    【解决方案1】:

    Thread.SetApartmentState() 方法在这里很重要。 Clipboard 是一个 COM 对象,它不是线程安全的。有很多 Windows 功能的行为是这样的,Drag+Drop 和 OpenFileDialog 等 shell 对话框就是其他示例。

    您不能设置线程池线程的单元状态,它始终是 MTA(多线程单元)。您可以在常规线程上,但额外的 STA 要求是您还可以泵送消息循环 (Application.Run)。这给你带来了完全相同的问题:你不能阻塞或花费很长时间来执行代码。

    简单的解决方案是在线程上执行任何需要很长时间的操作。并从 UI 线程进行剪贴板调用。使用 Control.BeginInvoke() 或者更好的 BackgroundWorker.RunWorkerCompleted。

    【讨论】:

    • arg,这将是一项艰巨的工作......我正在使用 SynchronizationContext 和这个 QueueUserWorkItem :(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多