Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 傻瓜公寓_.net_Multithreading - Fatal编程技术网

.net 傻瓜公寓

.net 傻瓜公寓,.net,multithreading,.net,Multithreading,我刚刚用以下方法纠正了一个错误: _Thread.SetApartmentState(ApartmentState.STA); 现在我想了解它的含义,以及它为什么有效 COM是.NET的祖父。他们对它有着非常崇高的目标,COM所做的但.NET完全忽略的事情之一就是为类提供线程保证。COM类可以发布它有什么样的线程需求。COM基础设施确保满足这些要求 这在.NET中是完全不存在的。例如,您可以在多个线程中使用队列对象,但如果您没有正确锁定,您的代码中将有一个很难诊断的严重错误 COM线程的确切细

我刚刚用以下方法纠正了一个错误:

_Thread.SetApartmentState(ApartmentState.STA);

现在我想了解它的含义,以及它为什么有效

COM是.NET的祖父。他们对它有着非常崇高的目标,COM所做的但.NET完全忽略的事情之一就是为类提供线程保证。COM类可以发布它有什么样的线程需求。COM基础设施确保满足这些要求

这在.NET中是完全不存在的。例如,您可以在多个线程中使用队列对象,但如果您没有正确锁定,您的代码中将有一个很难诊断的严重错误

COM线程的确切细节太大,无法放在文章中。我将集中讨论你问题的细节。创建COM对象的线程必须告诉COM它希望为具有受限线程选项的COM类提供何种支持。这些类中的绝大多数只支持所谓的单元线程,它们的接口方法只能从创建实例的同一线程安全地调用。换句话说,他们宣布“我不支持线程,请注意不要从错误的线程给我打电话”。即使客户端代码确实从另一个线程调用它

有两种,STA(单线程公寓)和MTA。它是在CoInitializeEx()调用中指定的,该函数必须由任何使用COM执行任何操作的线程调用。CLR在启动线程时会自动进行该调用。对于程序的主启动线程,它从main()方法的[StatThread]或[MTAThread]属性获取要传递的值。默认值为MTA。对于您自己创建的线程,它由您对SetApartmentState()的调用决定。默认值为MTA。线程池线程始终是MTA,不能更改

Windows中有许多代码需要STA。值得注意的例子是剪贴板、拖放和shell对话框(如OpenFileDialog)。还有很多你看不到的代码,比如UI自动化程序和观察消息的钩子。这些代码都不必是线程安全的,它的作者在不知道在哪个程序中使用它的情况下,很难保证代码的安全。因此,WPF或Windows窗体项目的UI线程必须始终是STA以支持此类代码,创建窗口的任何线程都必须是STA

但是,您向COM作出的线程为STA的承诺要求您遵守单线程单元合同。他们相当僵硬,当你违反合同时,你会很难诊断出问题。要求您在任何时间内都不会阻塞线程,并且您要泵送一个消息循环。WPF或Winforms的UI线程可以满足后一个要求,但如果创建自己的STA线程,则需要自己处理。对违约的常见诊断是僵局

顺便说一句,CLR中有相当多的内置支持来支持这些需求,帮助您避免麻烦。lock语句和WaitOne()方法在消息循环阻塞STA线程时泵送消息循环。然而,这只考虑了从不阻塞的需求,您仍然需要创建自己的消息循环。WPF和Winforms中的Application.Run()


我之前提供了一个答案,其中包含了更多关于使用消息循环保持COM快乐的重要性的细节。您会找到。

非常好的答案!我解决的错误是针对一个线程,我为一个长期运行的报表生成器创建了一个线程,它使用WPF控件构建报表的一部分,因此这是有意义的,尽管我不知道该线程上有一个消息循环。我认真地读了几遍MSDN帖子才能理解它,你的答案非常清楚,写得很好。非常感谢。邮局可以帮你