【发布时间】:2011-05-08 10:53:16
【问题描述】:
我刚刚用这个纠正了一个错误:
_Thread.SetApartmentState(ApartmentState.STA);
现在我想了解它的含义,以及它为什么起作用!
【问题讨论】:
-
This 发帖可以帮到你
标签: .net multithreading
我刚刚用这个纠正了一个错误:
_Thread.SetApartmentState(ApartmentState.STA);
现在我想了解它的含义,以及它为什么起作用!
【问题讨论】:
标签: .net multithreading
COM 是 .NET 的鼻祖。他们对它有相当崇高的目标,COM 所做但 .NET 完全跳过的一件事是为类提供线程保证。 COM 类可以发布它有什么样的线程要求。 COM 基础架构确保满足这些要求。
这在 .NET 中完全没有。例如,您可以在多个线程中使用 Queue 对象,但如果您没有正确锁定,您的代码中就会出现难以诊断的严重错误。
COM 线程的详细信息太大而无法在帖子中显示。我将专注于您的问题的具体细节。创建 COM 对象的线程必须告诉 COM 它想为具有受限线程选项的 COM 类提供什么样的支持。这些类中的绝大多数只支持所谓的单元线程,它们的接口方法只能从创建实例的同一线程安全地调用。换句话说,他们宣布“我不支持任何线程,请注意永远不要从错误的线程中调用我”。即使客户端代码实际上确实从另一个线程调用它。
有两种,STA(单线程单元)和MTA。它在 CoInitializeEx() 调用中指定,该函数必须由对 COM 执行任何操作的任何线程调用。每当启动线程时,CLR 都会自动进行该调用。对于程序的主启动线程,它从 Main() 方法的 [STAThread] 或 [MTAThread] 属性中获取要传递的值。默认为 MTA。对于您自己创建的线程,这取决于您对 SetApartmentState() 的调用。默认为 MTA。线程池线程始终是 MTA,无法更改。
Windows 中有很多代码需要 STA。您自己使用的值得注意的示例是剪贴板、拖放和外壳对话框(如 OpenFileDialog)。还有很多你看不到的代码,比如 UI 自动化程序和观察消息的钩子。这些代码都不必是线程安全的,它的作者在不知道它在哪个程序中使用的情况下很难保证它的安全。因此,WPF 或 Windows 窗体项目的 UI 线程必须始终是 STA 才能支持此类代码,任何创建窗口的线程也是如此。
您向 COM 承诺您的线程是 STA,但是 确实 要求您遵循单线程单元合同。它们非常僵硬,当您违反合同时,您可能很难诊断出问题。要求是您永远不会阻塞线程任何时间并且您泵送消息循环。 WPF 或 Winforms 的 UI 线程可以满足后一个要求,但如果您创建自己的 STA 线程,则需要自己处理。违约的常见诊断是死锁。
CLR 内置了相当多的支持来支持这些要求,顺便说一句,帮助您避免麻烦。 lock 语句和 WaitOne() 方法在 STA 线程上阻塞时会产生一个消息循环。然而,这只需要处理永不阻塞的要求,您仍然需要创建自己的消息循环。 WPF 和 Winforms 中的 Application.Run()。
我之前提供了一个答案,其中包含有关拥有消息循环以保持 COM 满意的重要性的更多详细信息。你会找到post here。
【讨论】: