UI线程的定义是什么?在.NET应用程序中是否只有一个UI线程?

UI线程的定义是什么?在.NET应用程序中是否只有一个UI线程?,.net,multithreading,.net,Multithreading,什么是UI线程?.NET应用程序中是否只有一个UI线程?已编辑以确保正确性: 在Windows窗体和WPF的类似概念中,每个活动应用程序都有一个UI线程 ie:当你启动应用程序时,有一个线程,当Application.Run(new Form1())运行时,它会变成一个UI线程;被称为 如果您尝试执行Application.Run(newform2());在运行时,您将得到“System.InvalidOperationException:在单个线程上启动第二个消息循环不是有效的操作。请改用Fo

什么是UI线程?.NET应用程序中是否只有一个UI线程?

已编辑以确保正确性:

在Windows窗体和WPF的类似概念中,每个活动应用程序都有一个UI线程

ie:当你启动应用程序时,有一个线程,当Application.Run(new Form1())运行时,它会变成一个UI线程;被称为

如果您尝试执行Application.Run(newform2());在运行时,您将得到“System.InvalidOperationException:在单个线程上启动第二个消息循环不是有效的操作。请改用Form.ShowDialog。”

如果您确实需要两个单独的表单来不共享同一个线程,则需要创建一个新线程,然后调用Application.Run(new MyForm())等。这并不常见。

(前面的简化)

UI线程是单个线程单元线程,用于创建各种用户界面对象(在Winforms中,这意味着控件)。按照惯例和规则,只能从用于创建控件的线程内访问控件;否则会产生意想不到的结果,从视觉上的怪异到崩溃


除非显式创建更多,否则Windows窗体应用程序中只有一个UI线程。虽然您可以创建另一个线程并启动消息循环,但您希望这样做的原因很少,而且两个不同的UI线程之间无法“对话”,就像任何其他线程都无法与UI线程对话一样。

UI线程有许多特殊的特征:

  • Windows有一个与线程关联的消息队列。一旦在线程上创建了第一个窗口,就会发生这种情况
  • 线程运行一个消息循环,允许Windows向Windows分派消息。只要调用Application.Run(),就会创建消息循环
  • COM在线程上初始化,请求单线程单元。STA是许多Windows功能正常工作所必需的,这些功能在设计上不是线程安全的。COM确保始终以线程安全的方式调用这些功能,根据需要将工作线程的调用封送到STA线程。这些功能的示例包括拖放、剪贴板、shell对话框(OpenFileDialog等)、ActiveX控件(如WebBrowser)、SetWindowsHookEx设置的窗口挂钩、屏幕阅读器使用的辅助功能提供程序、UI自动化提供程序。所有外部代码,都不是线程安全的
  • 线程从不阻塞任何操作,它保持响应,因此可以根据需要调度Windows消息,以保持用户界面响应和COM封送请求的流动。例如,明确禁止调用WaitHandle.WaitAny(),并生成异常。CLR对WaitOne()和锁有特定的支持,它通过内部消息循环来避免死锁
进程的启动线程几乎总是被选为UI线程,尽管这不是一个硬性要求。STA状态由Main()方法上的[STAThread]属性选择

您可以通过确保满足上述要求来创建UI线程。在Winforms应用程序中可能是这样的:

    var ui = new Thread(() => { Application.Run(new Form2()); });
    ui.SetApartmentState(ApartmentState.STA);
    ui.Start();

这将创建第二个窗口,在其自己的UI线程上运行。这种安排的一个典型问题是,现在有两个单独的窗口,它们根本没有关联。第二个窗口不能归第一个窗口所有,它有自己的Z顺序,独立于第一个窗口。用户很难处理。SystemEvents.UserPreferenceChanged事件值得注意,它将不可避免地在错误的线程上触发其事件,这很容易导致死锁。很多WinForms控件都订阅了它。除了在极少数情况下,如启动屏幕,这根本不能改善用户界面

事实并非如此。不同的窗体,在Windows窗体中,都使用相同的线程。消息泵使它们都有响应。我把它颠倒过来了,模态对话框需要一个新线程,非模态对话框不需要一个新线程。问题仍然是,当从普通线程启动新表单时,它们可能会变成ui线程。这仍然是不真实的。从新线程“启动表单”,如果不特别注意启动消息循环,将导致各种问题,包括(在大多数情况下)默认情况下由于缺少STA而导致崩溃。您可能是对的。在过去的一个案例中,我试图显示一个表单,但在运行时遇到一个错误,告诉我我不能在同一个ui线程上打开两个表单,我试图在这里找到注释,但我没有发现。只是编辑了我的帖子,我混淆了应用程序。使用form.show运行。+1提到你可以这样做,但是这很少是应该做的事情……那么,当你在一个STAThread内执行new Thread().Start()时会怎样呢?@griver:这会启动一个新线程,但它与UI线程完全分离。在任意位置执行新线程启动会创建一个新的、不相关的线程。@里德:你的意思是,如果我在线程内创建一个控件。启动,该控件将不会附加任何消息泵?@Griver:是的。如果您尝试将其添加到其他表单,则会出现错误。总的来说,这是个坏主意。(您需要将线程创建为STA线程,然后向线程中添加消息泵,然后创建表单。这可以让您启动新的UI线程,但这通常不是一个好主意—这样做的正当理由很少—因为您几乎总是能更好地推动“工作”安装到后台线程上并保留单个UI线程)