C#中使用事件机制实现线程间的通信

6 篇文章 0 订阅

转自:https://www.jianshu.com/p/8faae685a468

作者:桂慧要努力当个攻城师
链接:https://www.jianshu.com/p/8faae685a468
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

需要注意的点:订阅的方法仍是由主线程执行的(使用Control.Invoke()调用);

以下为转载内容:

---------------------

在图形界面中的运用程序中,通常是主线程负责UI人机交互,而将需要循环执行和耗资源的逻辑代码和复杂的业务实现以及数据交互放到单独一个线程里运行。这样可以保证主线程UI可以正常进行人机交互。
而线程之间的数据交互,就涉及了线程通信。这里将通过一个给MCU升级固件程序的IAP(在应用编程)的一个用C#写的上位机软件的实现原理,来说明如何通过事件的机制来实现线程之间的通信。

关于事件和委托的概念

事件(Event)用于进程间通信。
委托(Delegate)是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。

通过事件使用委托

事件在类中声明且生成,且通过使用同一个或其他类中的委托与事件处理程序关联。这被称为 发布器(publisher) 类。其他接受该事件的类被称为 订阅器(subscriber) 类。事件使用 发布-订阅(publisher-subscriber) 模型。

  • 发布器(publisher) 是一个包含事件和委托定义的对象。事件和委托之间的联系也定义在这个对象中。发布器(publisher)类的对象调用这个事件,并通知其他的对象。
  • 订阅器(subscriber) 是一个接受事件并提供事件处理程序的对象。在发布器(publisher)类中的委托调用订阅器(subscriber)类中的方法(事件处理程序)。

线程使用事件通信的基本流程

线程间基于事件机制通信的基本流程

案例说明

在IAP上位机应用中,当用户通过窗体配置好各项参数,点击开始按钮后,便通过串口尝试和MCU进行通信,如果通信握手正确,便开始向MCU发送需要更新的固件数据,这时窗体程序需要显示下载的进度和结果。

正在更新.png

在这个应用里,和MCU之间的串口通信是在子线程实现的,然而在UI应用中,子线程尝试更新还不属于自身线程的UI资源是不被允许的。
于是我便用了事件的机制,通过子线程将下载进度通过事件的形式发布出去,在主线程里订阅这个事件以及声明委托和定义事件的处理方法。在事件处理方法里获取下载进度,然后更新进度条。

主要的实现代码

声明事件

public event EventHandler NowDownloadProgressEvent;

在串口通信的线程类中声明当前下载进度事件

发布事件

int progress = (int)(((float)dataSize * packetNumber) / fileStream.Length * 100);
NowDownloadProgressEvent.Invoke(progress, new EventArgs());

当子线程开始与MCU通信,进行固件更新时,每循环发送完一个包,计算一次进度值,并将进度值以事件的形式发布出去。

事件订阅

downloadThread = new System.Threading.Thread(ymodem.YmodemUploadFile);
ymodem.NowDownloadProgressEvent += new EventHandler(NowDownloadProgressEvent);
ymodem.DownloadResultEvent += new EventHandler(DownloadFinishEvent);

主线程在启动子线程更新固件前,先订阅事件。这样子主线程就可以根据子线程发布的相关事件,进行一系列动作。

声明委托和定义事件处理方法

region 下载进度委托及事件响应
private delegate void NowDownloadProgress(int nowValue);
private void NowDownloadProgressEvent(objectsender,EventArgs e)
{
     int value = Convert.ToInt32(sender); 
     NowDownloadProgress count  = newNowDownloadProgress(UploadFileProgress);
     this.Invoke(count, value);
}
private void UploadFileProgress(int count)
{
         DownloadProgressBar.Value = count;
}
#endregion

主线程的类中,声明下载进度的委托和响应事件的方法。

至此就已经实现了线程间的基于事件机制的通信了。当然线程之间的通信出了事件,还有类似信号量,互斥锁,共享内存,消息队列等。而具体是使用哪一种,则是需要根据实际业务需求来选择。

 

关于事件总线的简单实现:

https://www.cnblogs.com/MuNet/p/8546362.html

https://www.cnblogs.com/zhangweizhong/p/8544158.html

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值