一、简介
[WinForm]关于InvokeRequired与Invoke_Jlins的博客-优快云博客_invokerequired
c#是禁止夸线程直接访问控件。
c#是禁止夸线程直接访问控件。
c#是禁止夸线程直接访问控件。
在C#中,主线程和工作线程是两种不同类型的线程,它们在应用程序中的作用有很大的区别。在理解他们的区别后,就能理解为什么要有InvokeRequired。
C# 主线程和工作线程、为什么要有InvokeRequired_c# invokerequired-优快云博客
主线程 (UI线程)
主线程(或UI线程)是应用程序启动时创建的线程,通常用于执行应用程序的用户界面(UI)的事件和操作。主线程负责处理UI元素的更新、事件响应、用户交互等任务。所有UI操作都必须在主线程上执行,以保持UI的响应性和同步。
工作线程 (后台线程)
工作线程(或后台线程)是专门用于执行后台任务和长时间运行操作的线程。工作线程不会直接与UI元素进行交互,而是负责执行诸如文件操作、网络通信、数据计算等不涉及UI更新的任务。工作线程可以独立于主线程运行,不会阻塞UI的响应。
区别
用途:主线程用于处理UI事件和更新,工作线程用于执行后台任务。
访问UI元素:只有主线程可以安全地访问和更新UI元素。工作线程不能直接访问UI元素,否则会抛出异常。
阻塞UI:长时间运行的任务或后台计算应放在工作线程上执行,以避免阻塞主线程,确保UI的响应性。
同步:主线程和工作线程之间的数据交换和通信需要适当的同步机制,以避免竞态条件和死锁。
创建和管理:主线程由操作系统和.NET运行时创建,而工作线程需要程序员显式创建和管理。
生命周期:主线程的生命周期与应用程序的启动和关闭相关,而工作线程的生命周期由程序员控制。
资源消耗:创建和管理工作线程会消耗更多的系统资源,因为每个线程都有自己的栈和上下文切换开销
个数:一个程序,通常只有1个主线程(UI线程),但是有多个工作线程
可以使用控件的InvokeRequired
属性检查,如果为true,则需要通过Invoke
方法对控件进行调用
如果从线程外操作windows窗体控件,那么就需要使用Invoke
或者BeginInvoke
方法,通过一个委托把调用封送到控件所属的线程上执行。
二、为什么要有InvokeRequired
在C#中,InvokeRequired是一个属性,它属于Control类。这个属性用来检查一个控件的当前线程是否是创建该控件的线程(UI线程)。如果不是,那么你可能需要使用Invoke或BeginInvoke方法在正确的线程上执行操作,唤醒UI线程来对控件内容进行更新,以避免跨线程操作异常。
Control.InvokeRequired
InvokeRequired是为了解决这个问题而产生的,当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它。那么就需要使用
Invoke
或者BeginInvoke
方法,通过一个委托把调用封送到控件所属的线程上执行。
InvokeRequired==true
Windows 中的控件被绑定到特定的线程,没有线程安全性,因此从另外一个线程调用控件的方法就必须使用控件的一个invoke 方法来将调用封到适当的线程,这个做法保证了控件的安全。
public void DoSomething()
{
if(this.InvokeRequired==true)
{
// InvokeRequired==true,说明是非创建线程在访问当前的UI控件
this.BeginInvoke(new MethodInvoker(() => {
// DoMywork();
}));
}
else
{
// DoMywork();
}
}
三、Control.InvokeRequired
的设计原理
确保线程安全:深入理解.Net开发中 `Control.InvokeRequired` 属性-优快云博客
1. 线程模型
Control.InvokeRequired 属性的存在就是为了确保线程安全,避免多线程环境下对 UI 的不安全操作。
2. 控件的线程关联
每个控件都有一个与之相关联的线程,这通常是创建该控件的线程。为了保证线程安全,所有对控件的操作都必须在其创建线程上进行。因此,当其他线程尝试操作这些控件时,需要通过 Invoke 方法来切换到正确的线程。
3. Invoke 方法
Control 类提供了 Invoke 方法,用于在创建控件的线程上执行指定的委托。通过 Invoke 方法,我们可以确保操作在正确的线程上执行,从而避免线程安全问题。
4. InvokeRequired 属性
InvokeRequired 属性用于检查当前线程是否是控件的创建线程。如果返回 true,则表示必须使用 Invoke 方法来将操作传递到控件的创建线程上执行。如果返回 false,表示当前线程就是创建控件的线程,可以直接执行操作。