C# Delegate(委托)与多线程

很多时候写windows程序都需要结合多线程,在.net中用如下得代码来创建并启动一个新的线程。
    public void ThreadProc();
    Thread thread = new Thread(new ThreadStart(ThreadProc));
    thread.IsBackground = true;
    thread.Start();
    但是很多时候,在新的线程中,我们需要与UI进行交互,在.net中不允许我们直接这样做。可以参考MSDN中的描述:
    “Windows 窗体”使用单线程单元 (STA) 模型,因为“Windows 窗体”基于本机 Win32 窗口,而 Win32 窗口从本质上而言是单元线程。STA 模型意味着可以在任何线程上创建窗口,但窗口一旦创建后就不能切换线程,并且对它的所有函数调用都必须在其创建线程上发生。除了 Windows 窗体之外,.NET Framework 中的类使用自由线程模型。
    STA 模型要求需从控件的非创建线程调用的控件上的任何方法必须被封送到(在其上执行)该控件的创建线程。基类 Control 为此目的提供了若干方法(Invoke、BeginInvoke 和 EndInvoke)。Invoke 生成同步方法调用;BeginInvoke 生成异步方法调用。
    Windows 窗体中的控件被绑定到特定的线程,不具备线程安全性。因此,如果从另一个线程调用控件的方法,那么必须使用控件的一个 Invoke 方法来将调用封送到适当的线程。
    正如所看到的,我们必须调用Invoke方法,而BeginInvoke可以认为是Invoke的异步版本。调用方法如下:
    public delegate void OutDelegate(string text);
    public void OutText(string text)
    {
         txt.AppendText(text);
         txt.AppendText( "\t\n" );
    }
    OutDelegate outdelegate = new OutDelegate( OutText );
    this.BeginInvoke(outdelegate, new object[]{text});

如果我们需要在另外一个线程里面对UI进行操作,我们需要一个类似OutText的函数,还需要一个该函数的委托delegate,当然,这里展示的是自定义的,.net中还有很多其他类型的委托,可以直接使用,不需要而外声明。例如:MethodInvoker和EventHandler,这两种类型委托的函数外观是固定的,MethodInvoker是void Function()类型的委托,而EventHandler是void Function(object, EventArgs)类型的委托,第一个不支持参数,第二中的参数类型和数量都是固定的,这两种委托可以很方便的调用,但是缺乏灵活性。请注意 BeginInvoke前面的对象是this,也就是主线程。现在再介绍Control.InvokeRequired,Control是所有控件的基类,对于这个属性MSDN的描述是:
    获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用 Invoke 方法,因为调用方位于创建控件所在的线程以外的线程中。
该属性可用于确定是否必须调用 Invoke 方法,当不知道什么线程拥有控件时这很有用。
    也就是说通过判断InvokeRequired可以知道是否需要用委托来调用当前控件的一些方法,如此可以把OutText函数修改一下:
    public delegate void OutDelegate(string text);
    public void OutText(string text)
    {
         if( txt.InvokeRequired )
         {
             OutDelegate outdelegate = new OutDelegate( OutText );
             this.BeginInvoke(outdelegate, new object[]{text});
             return;
         }
         txt.AppendText(text);
         txt.AppendText( "\t\n" );
    }
    注意,这里的函数没有返回,如果有返回,需要调用Invoke或者EndInvoke来获得返回的结果,不要因为包装而丢失了返回值。如果调用没有完成,Invoke和EndInvoke都将会引起阻塞。
    现在如果我有一个线程函数如下:
    public void ThreadProc()
    {
         for(int i = 0; i < 5; i++)
         {
             OutText( i.ToString() );
             Thread.Sleep(1000);
         }
    }
    如果循环的次数很大,或者漏了Thread.Sleep(1000);,那么你的UI肯定会停止响应,想知道原因吗?看看BeginInvoke前面的对象,没错,就是this,也就是主线程,当你的主线程不停的调用OutText的时候,UI当然会停止响应。
    与以前VC中创建一个新的线程需要调用AfxBeginThread函数,该函数中第一个参数就是线程函数的地址,而第二个参数是一个类型为 LPVOID的指针类型,这个参数将传递给线程函数。现在我们没有办法再使用这种方法来传递参数了。我们需要将传递给线程的参数和线程函数包装成一个单独的类,然后在这个类的构造函数中初始化该线程所需的参数,然后再将该实例的线程函数传递给Thread类的构造函数。代码大致如下:
    public class ProcClass
    {
         private string procParameter = "";
         public ProcClass(string parameter)
         {
             procParameter = parameter;
         }
         public void ThreadProc()
         {
         }
    }
    ProcClass threadProc = new ProcClass("use thread class");
    Thread thread = new Thread( new ThreadStart( threadProc.ThreadProc ) );
    thread.IsBackground = true;
    thread.Start();
    就是这样,需要建立一个中间类来传递线程所需的参数。
    那么如果我的线程又需要参数,又需要和UI进行交互的时候该怎么办呢?可以修改一下代码:
    public class ProcClass
    {
         private string procParameter = "";
         private Form1.OutDelegate delg = null;
         public ProcClass(string parameter, Form1.OutDelegate delg)
         {
             procParameter = parameter;
             this.delg = delg;
         }
         public void ThreadProc()
         {
             delg.BeginInvoke("use ProcClass.ThreadProc()", null, null);
         }
    }
    ProcClass threadProc = new ProcClass("use thread class", new OutDelegate(OutText));
    Thread thread = new Thread( new ThreadStart( threadProc.ThreadProc ) );
    thread.IsBackground = true;
    thread.Start();
    //-----------------------以下为自己写的异步委托的例子------------------------
      namespace PhsControlDelegate
     {
          public partial class Form2 : Form
          {
               PhsControl.phsControl phsObj = new PhsControl.phsControl();
               public delegate void OperationDelegate(string strMessage);

public Form2()
               {
                    phsObj.OnJieShouDuanXin +=new PhsControl.JieShouDXHandler(phsObj_OnJieShouDuanXin);
               }
   
               public void SetText(string strMessage)
               {
                    txtReceive.AppendText(strMessage);
               }

protected void phsObj_OnJieShouDuanXin(Object sender, PhsControl.jsSmsArgs e)
               {
                    OperationDelegate optionDelgate = new OperationDelegate(SetText);

this.BeginInvoke(optionDelgate, new object[] { e.dhHaoMa + " " + e.dxNeiRong + "\t\n" });
               }
          }
     }

转自 http://kenter1643.javaeye.com/blog/415701

转载于:https://www.cnblogs.com/Deckard/archive/2010/05/19/1739116.html

C# Delegate(委托)与多线程相关推荐

  1. 异步委托实现多线程winform控件编程

            private void button1_Click(object sender, EventArgs e)         {             ThreadStart ts  ...

  2. Strategy模式与Delegate委托

    Strategy模式是对算法的封装.即使是一个计算行为,如果其实现有其多样性,为达到易扩展的目的,我们也有必要将其抽象出来,以接口的形式来定义.由于充分利用了面向对象的多态性,在调用该行为时,其具体的 ...

  3. delegate委托

    delegate委托: 三个概念: C# 中的委托类似于 C 或 C++ 中的函数指针. 委托是面向对象.类型安全的,并且是安全的. 委托和接口的类似之处是:它们都允许分隔规范和实现. 一个原则: 被 ...

  4. 【C#学习】delegate(委托) 和 event(事件)

    C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针.委托(Delegate) 是存有对某个方法的引用的一种引用类型变量.引用可在运行时被改变.在C#中方法不能作为参数直接传递,必须 ...

  5. 转:终于会用c#中的delegate(委托)和event(事件)了

    第一个例子: public class DelegateTest {// 声明delegate对象 public delegate void CompareDelegate(int a,int b); ...

  6. Delegate委托的使用

    Delegate委托的使用 委托的说明 委托(delegate)是Cocoa的一个术语,表示将一个对象的部分功能转交给另一个对象. 比如对象A希望对象B知道将要发生或已经发生某件事情,对象A可以把对象 ...

  7. UE4 C++:Delegate委托

    目录 概念 定义 声明委托 单播委托 声明宏 绑定委托 执行函数 用法示例 不带参数Delegate 带参数Delegate 传递有效负载数据 多播委托 声明宏 绑定多播委托 多播执行 动态委托 声明 ...

  8. C#中利用委托实现多线程跨线程操作

    在使用VS2005的时候,如果你从非创建这个控件的线程中访问这个控件或者操作这个控件的话就会抛出这个异常.这是微软为了保证线程安全以及提高代码的效率所做的改进,但是也给大家带来很多不便. 其实解决这个 ...

  9. 多线程(一)——委托与多线程

    目录 委托的使用 委托的概念,简单匿名函数与lamda表达式使用 委托的定义与使用 多播委托 泛型委托 匿名方法 Lamda表达式 举例 扩展方法 winform间窗体传值 传统方法 使用委托 事件方 ...

最新文章

  1. 轰动程序员圈的大事:女程序员将代码写到退休,返聘再续传奇
  2. UVa 11520 Fill the Square 填充正方形
  3. 计算机科学的理论基础
  4. MapReduce案例-wordcount-步骤分析
  5. ASP.NET MVC+EF框架+EasyUI实现权限管理系列(13)-权限设计
  6. sketch里的ios控件_30个让你眼前一亮的iOS Swift UI控件!
  7. python图像处理:一福变五福
  8. loadrunner java_如何使用LoadRunner开发JAVA Vuser
  9. Android中MediaRecorder.stop()报错 java.lang.RuntimeException: stop failed.
  10. 如何在网页中每小时更新一次数据?
  11. 关于sizeof(struct student)的问题
  12. 信创操作系统--统信UOS桌面版(多媒体软件:图像查看、处理,音频播放、录音机)
  13. PDMS二次开发(二十)——关于1.0.2.0版本升级内容的说明
  14. 计算机网络 『内部网关协议IGP中的路由信息协议RIP』
  15. Quartus II下载器件库
  16. 智能网联汽车信息安全学术研究现状
  17. brew 一直等待_58岁上海股神自爆交易铁则:80%时间的等待+20%的时间操作,精髓...
  18. 谈PS-based架构的线扫描(Line-scan)影像检测系统
  19. 测试飞机高度和速度的软件,测量飞行的高度、速度和方向
  20. html是一种通用的方法来,()是以一种完全通用的方法来设计函数或类而不必预先说明将被使用的每个对象的类型。A.模板B.类C....

热门文章

  1. python日志模块为什么打印到界面_如何将外部模块的日志消息打印到主Python模块的终端窗口?...
  2. c程序设计语言第五章,c程序设计语言第五章第7题答案
  3. fedora apache php,Fedora 20下安装搭建LAMP环境Apache+MySQL+PHP
  4. Lucene——Field.Store(存储域选项)及Field.Index(索引选项)
  5. 深度探索c++对象模型读书笔记:Data语意学-Data Member的绑定
  6. IIS6、7添加反向代理的步骤
  7. CI 模型公用查询函数
  8. 运动,由Silverlight助力 / Sports, Powered by Silverlight
  9. .net框架读书笔记---引用参数(ref/out)
  10. Android构建boot.img(一):root目录与ramdisk.img的生成