C#线程中安全访问控件(重用委托,避免繁复的delegate,Invoke)总结
1.第一种,不安全,当线程过多后,timer控件和线程中同时访问窗体控件时,有时会出现界面重绘出错。
public frmMain() { InitializeComponent(); System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls =false; }
2.避免繁复的delegate,Invoke,推荐
- public static class ControlCrossThreadCalls
- {
- public delegate void InvokeHandler();
-
- ///
- /// 线程安全访问控件,扩展方法 .net 3.5下用Lambda简化跨线程访问窗体控件,避免繁复的delegate,Invoke
- /// this.SafeInvoke(() =>
- /// {
- /// tsStatus.Text = one.Email + " 开始任务....";
- /// });
- ///
- //public static void SafeInvoke(this Control control, InvokeHandler handler)
- //{
- // if (control.InvokeRequired)
- // {
- // control.Invoke(handler);
- // }
- // else
- // {
- // handler();
- // }
- //}
-
- ///
- /// .net2.0线程安全访问扩展方法///
- /// ControlCrossThreadCalls.SafeInvoke(this.tsStatus, new ControlCrossThreadCalls.InvokeHandler(delegate()
- /// {
- /// tsStatus.Text = one.Email + " 开始任务...";
- /// }));
- public static void SafeInvoke(Control control, InvokeHandler handler)
- {
- if (control.InvokeRequired)
- {
- control.Invoke(handler);
- }
- else
- {
- handler();
- }
- }
- }
最新代码如下
- public static class CrossThreadCalls
- {
- public delegate void InvokeHandler();
-
- ///
- /// .net2.0中线程安全访问控件扩展方法,可以获取返回值,可能还有其它问题
- ///
- /// CrossThreadCalls.SafeInvoke(this.statusStrip1, new CrossThreadCalls.InvokeHandler(delegate()
- /// {
- /// tssStatus.Text = "开始任务...";
- /// }));
- /// CrossThreadCalls.SafeInvoke(this.rtxtChat, new CrossThreadCalls.InvokeHandler(delegate()
- /// {
- /// rtxtChat.AppendText("测试中");
- /// }));
- /// 参考:http://wenku.baidu.com/view/f0b3ac4733687e21af45a9f9.html
- ///
- public static void SafeInvoke(Control control, InvokeHandler handler)
- {
- if (control.InvokeRequired)
- {
- while (!control.IsHandleCreated)
- {
- if (control.Disposing || control.IsDisposed)
- return;
- }
- //control.Invoke(handler);
- IAsyncResult result = control.BeginInvoke(handler);
- control.EndInvoke(result);//获取委托执行结果的返回值
- }
- else
- {
- handler();
- }
- }
-
- ///
- /// 线程安全访问控件,扩展方法.net3.5用Lambda简化跨线程访问窗体控件,避免重复的delegate,Invoke
- /// this.statusStrip1.SafeInvoke(() =>
- /// {
- /// tsStatus.Text = "开始任务....";
- /// });
- /// this.rtxtChat.SafeInvoke(() =>
- /// {
- /// rtxtChat.AppendText("测试中");
- /// });
- ///
- //public static void SafeInvoke(this Control control, InvokeHandler handler)
- //{
- // if (control.InvokeRequired)
- // {
- // control.Invoke(handler);
- // }
- // else
- // {
- // handler();
- // }
- //}
- }
更正一个我发现的C#多线程安全访问控件普遍存在的问题,仅供参考,在网上搜索多线程访问控件,发现很多都是这种类似的写法
http://msdn.microsoft.com/zh-cn/library/ms171728.aspx
private void SetText(string text) { // InvokeRequired required compares the thread ID of the // calling thread to the thread ID of the creating thread. // If these threads are different, it returns true. if (this.textBox1.InvokeRequired) { SetTextCallback d = new SetTextCallback(SetText); this.Invoke(d, new object[] { text }); } else { this.textBox1.Text = text; } }
注意红色部分,这样写几个线程同时操作时问题不是很大,但是当我几10个几100个线程频繁操作时,就出现了System.OutOfMemoryException这个异常,猜测可能是线程堵塞,同时造成cpu很高,内存成倍增长。
来自博客:
http://www.cnblogs.com/slyzly/articles/2121436.html