Answers:
COM是.NET的祖父。他们有很高的目标,COM所做的事情之一,但.NET完全跳过了,它为类提供了线程保证。COM类可以发布它具有什么样的线程要求。并且COM基础结构可确保满足这些要求。
.NET中完全没有此功能。例如,您可以在多个线程中使用Queue <>对象,但是如果未正确锁定,则代码中将出现一个令人讨厌的错误,很难诊断。
COM线程的详细信息太大,无法放入帖子中。我将重点介绍您的问题。创建COM对象的线程必须告诉COM它希望为具有受限线程选项的COM类提供什么样的支持。这些类中的绝大多数仅支持所谓的Apartment线程,它们的接口方法只能从创建该实例的同一线程中安全地调用。换句话说,他们宣布“无论如何我都不支持线程,请当心不要从错误的线程打电话给我”。即使客户端代码确实确实是从另一个线程调用它的。
有两种,STA(单线程公寓)和MTA。它在CoInitializeEx()调用中指定,该函数必须由对COM进行任何操作的任何线程调用。每当启动线程时,CLR都会自动进行该调用。对于程序的主启动线程,它从Main()方法上的[STAThread]或[MTAThread]属性获取要传递的值。默认值为MTA。对于您自己创建的线程,取决于调用SetApartmentState()的方式。默认值为MTA。线程池线程始终是MTA,无法更改。
Windows中有很多需要STA的代码。您将使用的著名示例是剪贴板,拖放和外壳对话框(如OpenFileDialog)。还有很多您看不到的代码,例如UI Automation程序和观察消息的钩子。这些代码都不必是线程安全的,它的作者在不知道使用哪个程序的情况下很难使其安全。因此,与创建窗口的任何线程一样,WPF或Windows Forms项目的UI线程必须始终为STA以支持此类代码。
您向COM承诺您的线程是STA,但是确实要求您遵循单线程单元协定。它们非常僵硬,当您违反合同时,您可能会很难诊断问题。要求是您绝不会在任何时间段内阻塞线程,并且泵送消息循环。WPF或Winforms的UI线程可以满足后者的要求,但是如果您创建自己的STA线程,则需要自己进行维护。打破合同的常见诊断是死锁。
内置了很多CLR支持这些需求,帮助您摆脱麻烦。该锁声明和WaitOne的()方法泵消息循环,当它在一个STA线程块。但是,这仅满足了永不阻塞的要求,您仍然需要创建自己的消息循环。WPF和Winforms中的Application.Run()。