P.K*_*P.K 6 c# multithreading winforms
最近,我遇到了这种情况,我想在另一个线程(而不是主/ UI线程)上显示一个表单.我使用了线程池线程.该表单托管了一个RCW(用于COM组件).实例化表单给了我一个例外,即线程必须是STA.我试图将公寓状态设置为STA.但是,这也没有用.我最终明确地创建了一个线程并且有效(我使用ShowDialog并且不需要创建一个meesage泵).
编辑:
通过致电CoInitializeEx()选择公寓.线程池中的线程已经进行了该调用,在该调用之后无法更改公寓.
一个线程池选择MTA是有意义的,它毕竟是作为一个工作线程,不应该被需要编组的方法调用阻塞.选择单线程公寓还需要抽取消息循环.你永远不会期望线程池线程做的事情.
消息循环是必要的,因为这是COM用于封送在另一个线程上进行的调用的工具.该调用必须在STA线程中"注入",这只有在线程处于已知的静止状态时才有可能.如果不是,这样的电话会引起重大的重新入侵问题.即使线程正在循环,它有时也会这样做.
您不需要使用Application.Run()自行填充消息循环,因为ShowDialog()会启动自己的消息循环.这就是它如何获得模态.对话框关闭后,嵌套循环将立即退出.
您不应该依赖于线程池线程的特定行为.通常,在您不知情的情况下,线程池中的线程应该能够由CLR随时替换.线程池线程用于简单任务,最好是短期任务.
如果要对线程设置进行细粒度控制,则应创建专用线程.设置公寓状态就是一个很好的例子.
除了上述理论原因之外,你所尝试的内容还存在实际问题.在第二个线程上托管表单不起作用(没有大量额外的工作).表单必须在与消息泵相同的线程上运行 - 否则,它们将不会收到任何Windows消息,并且不会正确更新.
如果为该线程实现完整的消息泵,则可以在单独的线程上创建表单,但通常最好将工作项放在后台线程上,并使用异步编程技术来保持自UI线程的响应.