代码之家  ›  专栏  ›  技术社区  ›  P.K

为什么我们不能更改线程池线程的单元状态,为什么在使用ShowDialog时不需要messagepump?

  •  6
  • P.K  · 技术社区  · 15 年前

    最近,我遇到了这样一种情况,我希望在另一个线程(而不是主/UI线程)上显示表单。我用了一个线程池线程。表单承载了一个RCW(用于COM组件)。实例化表单给了我一个例外,线程必须是STA。我试图将公寓状态设置为STA。但是,这也不起作用。最后,我明确地创建了一个线程,并且成功了(我使用了ShowDialog,不需要创建meesage泵)。

    编辑:

    • 我知道线程池线程是MTA。但是,为什么不能设置为STA? 只是好奇而已。

    • 另一个突然出现在我脑海中的问题是:当使用Showdialog()来显示表单时,为什么不需要一个消息泵呢

    2 回复  |  直到 5 年前
        1
  •  11
  •   Hans Passant    15 年前

    通过调用CoInitializeEx()选择公寓。线程池中的线程已经进行了该调用,因此无法在该调用之后更改单元。

    线程池选择MTA是有道理的,毕竟它是作为工作线程使用的,不应该被需要封送的方法调用阻止。选择单线程单元还有一个额外的要求,即泵送一个消息循环。这是线程池线程永远不会做的事情。

    消息循环是必要的,因为COM使用它来封送在另一个线程上进行的调用。该调用必须“注入”到STA线程中,只有当线程处于已知的静态状态时才可能。如果不是这样的话,这样的电话将导致重大的再进入问题。即使线程正在泵送循环,它有时也会这样做。

    您不需要自己使用Application.Run()来启动消息循环,因为ShowDialog()会启动自己的消息循环。这就是它获得模态的方式。该嵌套循环将在对话框关闭时立即退出。

        2
  •  8
  •   Reed Copsey    15 年前

    您不应该依赖于线程池线程的特定行为。一般来说,线程池中的线程应该能够在您不知情的情况下随时被CLR替换。线程池线程用于简单任务,最好是短期任务。

    如果您想对线程设置进行细粒度控制,那么应该创建一个专用线程。设置公寓状态就是一个很好的例子。


    除了上述理论上的原因外,你所尝试的还有一个实际问题。在第二个线程上托管表单不起作用(如果没有大量额外的工作)。表单必须与消息泵在同一线程上运行-否则,它们将不会收到任何windows消息,也不会正确更新。

    如果您为一个单独的线程实现了一个完整的消息泵,那么您可以在该线程上创建一个表单,但通常最好将您的工作项放在后台线程上,并使用异步编程技术来保持您的自UI线程的响应性。