c#多线程通信之委托事件

在研究c# 线程之间通信时,发现传统的方法大概有三种:

  1. 全局变量,由于同一进程下的多个进程之间共享数据空间,所以使用全局变量是最简单的方法,但要记住使用volatile进行限制。
  2. 线程之间发送消息(这个随后文章中会讨论到)。
  3. CEvent为MFC中的一个对象,可以通过对CEvent的触发状态进行改变,从而实现线程间的通信和同步,这个主要是实现线程直接同步的一种方法。

本文介绍的一种方法是这三种之外的一种方法,本文中实例是通过创建一个线程类,通过委托事件把值传送到Form所在的类中,同时更新Form类中的一个控件(Label)中的值。

实现功能比较简单,目的是实现此功能,先把代码贴上:

MyThread.cs

using System;
using System.Threading;

namespace ThreadsComm
{
 public delegate void ReadParamEventHandler(string sParam);
 class MyThread
 {
  public Thread thread1;
  private static ReadParamEventHandler OnReadParamEvent;
  public MyThread()
  {
   thread1 = new Thread(new ThreadStart(MyRead));
   thread1.IsBackground = true;
   thread1.Start();
  }
  public event ReadParamEventHandler ReadParam
  {
   add { OnReadParamEvent += new ReadParamEventHandler(value);}
   remove{ OnReadParamEvent -= new ReadParamEventHandler(value);}
  }
  protected void MyRead()
  {
   int i = 0;
   while (true)
   {
    Thread.Sleep(1000);
    i = i + 1;
    OnReadParamEvent(i.ToString());//触发事件
   }
  }
 }
}

其中的

public event ReadParamEventHandler ReadParam
  {
   add { OnReadParamEvent += new ReadParamEventHandler(value);}
   remove{ OnReadParamEvent -= new ReadParamEventHandler(value);}
  }

这个需要说明一下:

add 上下文关键字用于定义一个自定义事件访问器,当客户端代码订阅您的事件时将调用该访问器。 如果提供自定义 add 访问器,还必须提供 remove 访问器。

remove 上下文关键字用于定义一个自定义事件访问器,当客户端代码取消订阅事件时将调用该访问器。 如果提供自定义 remove 访问器,还必须提供 add 访问器。
Form.cs

using System;
using System.Windows.Forms;

namespace ThreadsComm
{
 public partial class Form1 : Form
 {
  private static string param = "";
  public Form1()
  {
   InitializeComponent();
   MyThread thread1 = new MyThread();
   thread1.ReadParam += this.OnRead;
  }

  private void OnRead(string sParam)
  {
   param = sParam;
   Object[] list = { this,System.EventArgs.Empty};
   this.lblShow.BeginInvoke(new EventHandler(LabelShow), list);
  }
  protected void LabelShow(Object o, EventArgs e)
  {
   this.lblShow.Text = param;
  }
 }
}

其中的

 MyThread thread1 = new MyThread();
 thread1.ReadParam += this.OnRead;

是订阅线程类中的事件。

 this.lblShow.BeginInvoke(new EventHandler(LabelShow), list);

Invoke或者 BeginInvoke方法都需要一个委托对象作为参数。委托类似于回调函数的地址,因此调用者通过这两个方法就可以把需要调用的函数地址封送给界面线程。这些方法里面如果包含了更改控件状态的代码,那么由于最终执行这个方法的是界面线程,从而避免了竞争条件,避免了不可预料的问题。如果其它线程直接操作界面线程所属的控件,那么将会产生竞争条件,造成不可预料的结果。

使用 Invoke完成一个委托方法的封送,就类似于使用 SendMessage方法来给界面线程发送消息,是一个同步方法。也就是说在 Invoke封送的方法被执行完毕前, Invoke方法不会返回,从而调用者线程将被阻塞。

使用 BeginInvoke方法封送一个委托方法,类似于使用 PostMessage进行通信,这是一个异步方法。也就是该方法封送完毕后马上返回,不会等待委托方法的执行结束,调用者线程将不会被阻塞。但是调用者也可以使用 EndInvoke方法或者其它类似 WaitHandle机制等待异步操作的完成。

但是在内部实现上, Invoke和 BeginInvoke都是用了 PostMessage方法,从而避免了 SendMessage带来的问题。而 Invoke方法的同步阻塞是靠 WaitHandle机制来完成的。

想实验的读者可以建一个winform工程,采用上边的代码试验一下。

以上就是c#多线程通信之委托事件的详细内容,更多关于c#多线程委托事件的资料请关注我们其它相关文章!

(0)

相关推荐

  • 深入分析C#中的异步和多线程

    许多开发人员对异步代码和多线程以及它们的工作原理和使用方法都有错误的认识.在这里,你将了解这两个概念之间的区别,并使用c#实现它们. 我:"服务员,这是我第一次来这家餐厅.通常需要4个小时才能拿到食物吗?" 服务员:"哦,是的,先生.这家餐厅的厨房里只有一个厨师." 我:"--只有一个厨师吗?" 服务员:"是的,先生,我们有好几个厨师,但每次只有一个在厨房工作." 我:"所以其他10个穿着厨师服站在厨房里的人--什么

  • c# 并行和多线程编程——认识Parallel

    随着多核时代的到来,并行开发越来越展示出它的强大威力!使用并行程序,充分的利用系统资源,提高程序的性能.在.net 4.0中,微软给我们提供了一个新的命名空间:System.Threading.Tasks.这里面有很多关于并行开发的东西,今天第一篇就介绍下最基础,最简单的--认识和使用Parallel. 一. Parallel的使用 在Parallel下面有三个常用的方法invoke,For和ForEach. 1.Parallel.Invoke 这是最简单,最简洁的将串行的代码并行化. 在这里先

  • C# 多线程处理List数据的示例代码

    代码思路 将要处理的数据放到ConcurrentQueue中,然后开启多个线程去处理数据,处理完成后,再到队列中获取下一个待处理数据. ConcurrentQueue 表示线程安全的先进先出 (FIFO) 集合,属于 System.Collections.Concurrent 命名空间下的一个数据结构 直接上代码 /// <summary> /// 多线程处理数据(无返回值) /// </summary> /// <typeparam name="T"&g

  • C# 并行和多线程编程——Task进阶知识

    一.Task的嵌套 Task中还可以再嵌套Task,Thread中能不能这样做,我只能说我是没这样写过.Task中的嵌套,我感觉其实也可以分开来写,不过嵌套起来会方便管理一点.Task中的嵌套分为两种,关联嵌套和非关联嵌套,就是说内层的Task和外层的Task是否有联系,下面我们编写代码先来看一下非关联嵌套,及内层Task和外层Task没有任何关系,还是在控制台程序下面,代码如下: static void Main(string[] args) { var pTask = Task.Factor

  • C# 并行和多线程编程——并行集合和PLinq

    在上一篇博客,我们学习了Parallel的用法.并行编程,本质上是多线程的编程,那么当多个线程同时处理一个任务的时候,必然会出现资源访问问题,及所谓的线程安全.就像现实中,我们开发项目,就是一个并行的例子,把不同的模块分给不同的人,同时进行,才能在短的时间内做出大的项目.如果大家都只管自己写自己的代码,写完后发现合并不到一起,那么这种并行就没有了意义. 并行算法的出现,随之而产生的也就有了并行集合,及线程安全集合:微软向的也算周到,没有忘记linq,也推出了linq的并行版本,plinq - P

  • C# 并行和多线程编程——认识和使用Task

    对于多线程,我们经常使用的是Thread.在我们了解Task之前,如果我们要使用多核的功能可能就会自己来开线程,然而这种线程模型在.net 4.0之后被一种称为基于"任务的编程模型"所冲击,因为task会比thread具有更小的性能开销,不过大家肯定会有疑惑,任务和线程到底有什么区别呢? 任务和线程的区别: 1.任务是架构在线程之上的,也就是说任务最终还是要抛给线程去执行. 2.任务跟线程不是一对一的关系,比如开10个任务并不是说会开10个线程,这一点任务有点类似线程池,但是任务相比线

  • 详解C# 线程的挂起与唤醒

    如果说C#和C++有什么不同,博主不得不说,对于异步的支持程度是C#的一一个伟大的进步. 其实早期的C++都没有异步,并发的概念.博主第一次使用C++创建异步程序的时候,是使用boost库的内容进行实现的.相对而言,C#对于异步的支持可以说是相当的好.相信很多名词大家都很耳熟能详,比如说Thread,BeginInvoke,Delegate,backgroundworker等等...其实楼主在使用了这么多的异步操作过程中,还是觉得backgroudworker比较好用. 当然,我们今天要说的和上

  • c# 多线程处理多个数据的方法

    概述 多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术.具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能.具有这种能力的系统包括对称多处理机.多核心处理器以及芯片级多处理或同时多线程处理器.在一个程序中,这些独立运行的程序片段叫作"线程"(Thread),利用它编程的概念就叫作"多线程处理". 队列(Queue)代表了一个先进先出的对象集合.当您需要对各项进行先进先出的访问时,则使用队列.

  • C#-WinForm跨线程修改UI界面的示例

    背景 在我做WinForm开发的过程中,经常会遇到耗时操作或阻塞操作.他们会引发软件的卡顿甚至假死,严重影响软件的使用.因此,这类耗时或阻塞的操作一般都会使用异步的方式去执行,不影响主线程(UI线程)与用户间的交互.但多个线程竞争读写同一个资源往往会造成意想不到的意外结果,UI界面也是一种资源,所以跨线程修改UI界面往往被加以限制.而在Winform中,跨线程修改UI界面同样是不被允许的.在子线程中修改界面控件时Visual Studio会报出如下错误: 解决思路 .Net提供了很多跨线程修改U

  • c# Thread类线程常用操作详解

    创建线程 线程是通过扩展 Thread 类创建的.扩展的 Thread 类调用 Start() 方法来开始子线程的执行. 下面的程序演示了这个概念: class ThreadCreationProgram { public static void CallToChildThread() { Console.WriteLine("Child thread starts"); } static void Main(string[] args) { ThreadStart childref

随机推荐