首页 > 其他分享 >WinForm中的多线程

WinForm中的多线程

时间:2022-11-09 12:37:54浏览次数:81  
标签:控件 Invoke 句柄 InvokeRequired 线程 BeginInvoke 多线程 WinForm

使用BeginInvoke或Invoke

  • 作用
    • 在自己创建的非UI线程中,进行UI操作,比如更新UI上控件的状态。
    • Windows 窗体中的控件被绑定到特定的线程,不具备线程安全性。因此,如果从另一个线程调用控件的方法,那么必须使用控件的一个 Invoke 方法来将调用封送到适当的线程。
    • 如果已经创建控件的句柄,则除了 InvokeRequired 属性以外,控件上还有四个可以从任何线程上安全调用的方法,它们是: Invoke、BeginInvoke、 EndInvoke 和 CreateGraphics。 在后台线程上创建控件的句柄之前调用 CreateGraphics 可能会导致非法的跨线程调用。 对于所有其他方法调用,当从另一个线程进行调用时,应使用这些 Invoke 方法之一。如果控件句柄尚不存在,则 InvokeRequired 沿控件的父级链搜索,直到它找到有窗口句柄的控件或窗体为止。 如果找不到合适的句柄, InvokeRequired 方法将返回 false。
  • 也可以new一个Thread,在其中再使用BeginInvoke或Invoke
  • 这其实就是在自己创建的非UI线程中,又有一部分逻辑是要修改主UI线程的显示,那么就要用BeginInvoke来实现
    Thread t = new Thread(() =>
                {
                    // business logic
    
                    this.BeginInvoke(new Action(delegate ()
                    {
                       // ui logic
                    }));
    
                    // business logic
    
                    this.BeginInvoke(new Action(delegate ()
                    {
                       // ui logic
                    }));
                });
                t.Start();

     

  • 每个控件都有new、active、disposed三个状态
  • 调用前的检查
    • 否则可能会导致异常:Invoke or BeginInvoke cannot be called on a control until the window handle has been created. (在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke)
    • 因此需要一些属性用于确定是否必须调用 Invoke 方法,当不知道什么线程拥有控件时这很有用
      • InvokeRequired
        • 最好在调用的外层套一个InvokeRequired来判断当前是否必须使用Invoke或者BeginInvoke来做动作,为false时即可以直接做动作
        • 这意味着如果不需要 Invoke(调用发生在同一线程上),或者如果控件是在另一个线程上创建的但尚未创建控件的句柄,则InvokeRequired 可以返回 false。如果尚未创建控件的句柄,您就不能简单地在控件上调用属性、方法或事件。这可能导致在后台线程上创建控件的句柄,从而隔离不带消息泵的线程上的控件并使应用程序不稳定。
      • IsHandleCreated
        • 谨慎起见,还可以使用IsHandleCreated来判断该控件是否已经创建了关联的句柄
        • 当 InvokeRequired 在后台线程上返回 false 时,您也可以通过检查 IsHandleCreated 的值来避免上面这种情况。 如果尚未创建控件句柄,您必须等到控件句柄已创建,才能调用 Invoke 或 BeginInvoke。 通常,仅当在应用程序主窗体的构造函数中创建了后台线程时(如同在 Application.Run(new MainForm()) 中),在已经显示窗体或取消 Application.Run 之前,才会发生这种情况
      • 单从检查的角度来说,事实上IsHandleCreate比InvokeRequired要严格,前者为true时,后者肯定是true???;InvokeRequired为false的原因可能是IsHandleCreate为false或者根本不需要Invoke等。
      • 两者的用途不太一样,一个用于判断有没有必要使用Invoke等,一个用于判断控件是否有句柄,虽然两者存在上述关系,所以最好两个属性都进行判断,先后顺序个人感觉无所谓
    • if(control.IsDisposed || (!control.IsHandleCreated && !control.FindForm().IsHandleCreated))
      {
          // some exceptional condition:
          // handle in whatever way is appropriate for your app
          return;
      }
      
      if(control.InvokeRequired)
      {
          control.Invoke(action);
      }
      else
      {
          action();
      }

       

标签:控件,Invoke,句柄,InvokeRequired,线程,BeginInvoke,多线程,WinForm
From: https://www.cnblogs.com/hanzq/p/16873214.html

相关文章

  • 多线程的操作方式
    MAX_PRIOITY10 MIN_PRIOITY 1NORM_PRIOITY 5  getPriority();返回线程的优先级setPriority(intnewPriority)改变线程的优先级......
  • 尚硅谷java入门b站零基础 异常处理 +多线程+部分项目三 2022.3.26
    380如何自定义异常/**如何自定义异常类?*1.继承于现有的异常结构:RuntimeException、Exception*2.提供全局常量:serialVersionUID*3.提供重载的构造器**/publicc......
  • 线程同步-读者写者问题(多线程)
    任务描述:0推荐在openEuer上实现1描述操作系统中“读者-写者”问题,理解问题的本质,提交你理解或查找到的文本资料2利用多线程完成reader和writer3在main中测试若干个......
  • Linux多线程开发
    1.线程线程概述与进程(process)类似,线程(thread)是允许应用程序并发执行多个任务的一种机制。一个进程可以包含多个线程。同一个程序中的所有线程均会独立执行相同程序,且共享......
  • Winform CustomControl这样写
    WinformCustomControl这样写usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Data;usingSystem.Drawing;usingSystem.Text;us......
  • 读者-写者(多线程)
    目录问题描述问题分析伪代码伪代码描述相关函数代码实现问题描述有读者和写者两个并发进程,共享一个文件,当两个或以上的读进程同时访问共享数据时不会产生副作用,但若某......
  • GDB-2——GDB调试多线程
     一、简介前一博文实际上已经介绍了多线程的调试方法,这节专门进行一下总结。 二、调试多线程1.使用gdb将程序跑起来,然后按Ctrl+C将程序中断下来,使用infoth......
  • 一个超经典 WinForm 卡死问题的再反思
    一:背景1.讲故事这篇文章起源于昨天的一位朋友发给我的dump文件,说它的程序出现了卡死,看了下程序的主线程栈,居然又碰到了OnUserPreferenceChanged导致的挂死问题,真的是经......
  • java 多线程买票案例
    packagecom.tedu.threadStudy;publicclassstudyTicket{publicstaticvoidmain(String[]args){YouThreadyouThread=newYouThread();T......
  • C#里的多线程,一网打尽thread,task,parallel
    C#里的多线程,一网打尽1.Syncawait2.Thread3.Threadpool4.Task5.Parallel Tasktask=newTask(()=>{});task.Start();Tasktask=Task.Run(()=>{};TaskFactoryta......