`
emowuyi
  • 浏览: 1475453 次
文章分类
社区版块
存档分类
最新评论

多线程(异步委托)调用和控件响应问题

 
阅读更多
当系统要进行工作量较大的任务时,倾向于将该任务安排在一个优先级别相对较低的后台线程处理,这样UI线程或主线程还将可以响应用户的其他操作,使系统具有良好的交互性。下面以一个控件刷新的程序为例,讨论多线程和控件的关系。程序代码如下:
  1. usingSystem;
  2. usingSystem.Collections.Generic;
  3. usingSystem.ComponentModel;
  4. usingSystem.Data;
  5. usingSystem.Drawing;
  6. usingSystem.Text;
  7. usingSystem.Windows.Forms;
  8. usingSystem.Threading;
  9. namespaceWindowsApplication3
  10. {
  11. publicpartialclassFormTest:Form
  12. {
  13. privatedelegatevoidInvokeDelegate();
  14. privatedelegatevoidSetTextBoxHandler(TextBoxtb,stringstr);
  15. privateInvokeDelegateinvokeDelegate;
  16. privateSetTextBoxHandlerdeleChangeText;
  17. publicFormTest()
  18. {
  19. InitializeComponent();
  20. }
  21. privatevoidFormTest_Load(objectsender,EventArgse)
  22. {
  23. //初始化两个代理实例
  24. this.invokeDelegate=newInvokeDelegate(this.FunTest);
  25. this.deleChangeText=newSetTextBoxHandler(this.SetTextBoxValue);
  26. }
  27. privatevoidFunTest()
  28. {
  29. for(inti=0;i<100000;i++)
  30. {
  31. //搜索控件句柄,判断控件是否生成,不生成则返回false,此时就不能调用begininvoke方法了
  32. //另外,如果对if内部语句的调用发生在同一线程(即UI线程或主线程),则InvokeRequired将返回false;
  33. if(this.textBox1.InvokeRequired)
  34. {
  35. this.BeginInvoke(this.deleChangeText,newobject[]{this.textBox1,i.ToString()});
  36. //一定注意,Sleep的动作一定不能放在SetTextBoxValue()方法中,因为控件的BeginInvoke()会将SetTextBoxValue()方法
  37. //封送至后台线程,这就变成了在后台线程中让主线程Sleep300ms的时间,而不是让后台线程Sleep300ms了。
  38. Thread.Sleep(300);
  39. }
  40. else
  41. {
  42. this.SetTextBoxValue(this.textBox1,i.ToString());
  43. Thread.Sleep(300);
  44. }
  45. }
  46. }
  47. privatevoidSetTextBoxValue(TextBoxtb,stringstr)
  48. {
  49. tb.Text=str;
  50. tb.Refresh();
  51. //下面的句子表明,即使该方法被封送到后台线程后,该方法内的线程是主线程,而非后台线程
  52. //MessageBox.Show(Thread.CurrentThread.IsBackground.ToString());
  53. }
  54. //在后台线程中调用FunTest()
  55. privatevoidbutton1_Click(objectsender,EventArgse)
  56. {
  57. //使用异步调用,开辟后台线程
  58. this.invokeDelegate.BeginInvoke(null,null);
  59. }
  60. //在UI线程中调用FunTest()
  61. privatevoidbutton2_Click(objectsender,EventArgse)
  62. {
  63. this.FunTest();
  64. }
  65. //使用代理调用函数,结果同button2_Click()
  66. privatevoidbutton3_Click(objectsender,EventArgse)
  67. {
  68. this.invokeDelegate();
  69. }
  70. }
  71. }

代码的主要目的是,点击button,使得控件textbox控件的值从1刷新到100000,主要有三种方式,第一,异步委托调用;第二,直接调用;第三,代理同步调用。

经过试验发现一下特点:

第一,三者都可以刷新textbox,但是后面二者不能响应窗体其他事件,但使用异步委托的话,窗体可以相应拖放、点击button等事件,拖放窗体时,textbox仍持续刷新。

第二, 使用异步委托或者多线程调用FunTest()方法,涉及到对UI控件的操作,本例中表现为对textbox设置text属性及刷新,而在后台线程中操作控件很容易引起异常,使得线程使用不安全。一般情况下,不鼓励在后台线程中操作控件。.Net提供了Control.BeginInvoke()等方法来解决这一问题。倘若后台线程需要操作控件,则必须将这些操作函数绑定到一个代理D上,然后通过控件的BeginInvoke()方法调用,D作为该方法的一个参数。在例程中,操作控件的方法为SetTextBoxValue(),使用代理deleChangeText绑定,然后,通过BeginInvoke()调用。

第三, 控件的InvokeRequired属性的作用。如果FunTest()方法在非UI线程中执行,则InvokeRequired返回true,若在UI线程中执行,则返回false。在例子中使用if else流程控制语句,若FunTest()在后台线程中执行,则必须使用控件的BeginInvoke()方法,若FunTest()在UI线程中执行,则可直接调用控件操作方法,无需使用BeginInvoke()方法。注意FunTest()既可能在后台线程中调用,也可能在UI线程中调用,而在不同的线程内操作控件的方法有所不同,因此,必须使用InvokeRequired属性和if else来分别给出正确的调用方法。本例子中点击button2button3所调用的方法,就是else分支的方法,因为这两种调用方法不属于多线程调用。

第四, 关于FunTest()方法中的Thread.Sleep(300)。在不加这一sleep操作时,在对四台计算机的试验中,运行时,三台计算机的FormTest窗体可以拖动,一台不可以拖动。添加sleep操作后,所有计算机的FormTest窗口都可以拖动。我猜想,虽然实现的是多线程操作,但计算机的性能不同,是否能够响应窗体事件也不一样。当我不停的点击button1,不停的开辟新线程的时候,sleep参数设置为300时,最多开辟62个线程后,窗体不再响应事件,button1也无法再点击;当sleep设置为200时,不停点击button1,最多开辟61个线程,此后窗体不再响应事件。可见,虽然多线程可以提高UI线程的响应,但这并不是绝对的,随着计算机性能的下降,UI线程的响应能力就越差,直到无法响应。

第五, Thread.Sleep(300)的位置问题。是否可以将Thread.Sleep(300)放到SetTextBoxValue()方法中?实验证明,这样做是不行的,我们希望sleep的线程是后台线程而非UI线程,一旦Sleep()方法放到SetTextBoxValue()方法中,SetTextBoxValue()将被封送至后台线程中运行,然后这里的Sleep,实际上是UI线程的Sleep,而不是后台线程的Sleep了。

*当子线程是前台线程,则主线程结束并不影响其他线程的执行,只有所有前台线程都结束,程序结束

*当子线程是后台线程,则主线程的结束,会导致子线程的强迫结束

分享到:
评论

相关推荐

    VB.Net-C#多线程Thread-代理委托delegate编程

    最近收集的VB.Net-C#多线程Thread-代理委托delegate编程。文章列表: c#.net多线程同步.txt C#WebBrowser页面与WinForm交互技巧一.txt C#多线程编程-多细全.txt C#多线程编程简单实例.txt C#多线程窗体控件安全访问....

    多线程异步编程带进度条的利用Excel模版报表转换DEMO

    很专业的一个报表转换,多线程,异步AsynCallBack,委托的异步调用,winform皮肤控件,excel模版导出,导入,字符串的解析等高级技术完成的,本人原创,

    权威.NET多线程详解(源码示例)

    • 异步和多线程有什么关联 WinForm多线程编程篇 • 我的多线程WinForm程序老是抛出InvalidOperationException ,怎么解决? • Invoke,BeginInvoke干什么用的,内部是怎么实现的 • 每个线程都有消息队列吗? ...

    .net 线程详解 基础篇

    * 异步和多线程有什么关联 WinForm多线程编程篇 * 我的多线程WinForm程序老是抛出InvalidOperationException ,怎么解决? * Invoke,BeginInvoke干什么用的,内部是怎么实现的 * 每个线程都有消息队列吗? *...

    android开发教程之handle实现多线程和异步处理

    首先,在之前的基本控件,基本都是在Activity的onCreate(Bundle savedInstanceState)方法中调用和处理的,但是,在有些情况,比如在网络上下载软件等一些需要等待响应时间比较长的操作,如果同样放在Activity的该...

    (PFW/PowerUI)PB最强大的框架,没有之一

    3. httpclinet对象,能轻松的让你对接支付宝和微信,Demo内含支付宝和微信当面付功能,支持同步(实时调用-实时返回结果)和异步(先调用,后台订阅事件返回结果通知)调用 4. sciter和blink(chorm)界面引擎,可以...

    iOS 面试题

    7.请 分别简述 notification 的 同步和 异步的调用 方法 是广播模式/观察者模式,可以异步查看系统或者自定义一些事件 8.如何调用 UIView 的 drawrect 消息 定制uiview直接用图形画底层控件一般用drawRect:...

    COM与COM+从入门到精通(pdf版本,含源码)

    Win32多线程应用 线程COM组件 自动化与IDispatch 用VC++实现IDispatch ATL与自动化 Automation数据类型 再谈类型库 C++自动化客户机 VB自动化客户机 小结 第3章 用VB建立并使用COM服务器 选择COM...

    Visual C# 2005编程技巧大全 源码

    包括ToolStrip控件应用、泛型应用、注册表管理、WMI管理规范使用、XML文件处理、多线程处理、程序异常处理、文件压缩及解压缩、文件加密解密、文件访问权限、API函数调用、指针调用、GDI+图像文字特效处理、数理更新...

    北京中科信软 Visual Basic.NET培训

    Web Service中的异步调用,状态管理 事务处理,安全性,自定义身份验证 Visual Studio Team System 中的单元测试与Web测试 案例分析:基于.NET2.0的大型电子商务系统 五 Windows 应用(Windows Forms) 创建...

    HslCommunicationDemo.zip_modbus TCP_plc 三菱_三菱modbus tcp_控件库_西门子m

    功能列表----(更新不及时,请参照上面的demo界面) 日志记录功能 同步网络通讯功能 文件管理引擎 异步网络通讯功能 三菱PLC访问 西门子PLC访问 欧姆PLC访问 ...多线程任务功能 CRC16校验 常用控件库

    VC++常用的共用函数100多页

    相关网站 7 设置窗口最大最小 7 ...更改窗口控件的能动和不能动(以按钮控件为例) 120 窗口响应键盘事件 120 密码框输入受保护 121 最高窗口的实现 122 实现窗口动态写入汉字和改变汉字颜色形状 123

    VC++常用功能实例

    相关网站 7 设置窗口最大最小 7 ...更改窗口控件的能动和不能动(以按钮控件为例) 120 窗口响应键盘事件 120 密码框输入受保护 121 最高窗口的实现 122 实现窗口动态写入汉字和改变汉字颜色形状 123

Global site tag (gtag.js) - Google Analytics