学更好的别人,
做更好的自己。
——《微卡智享》
本文长度为3106字,预计阅读8分钟
前言
前一篇《学习|C#的EventHandler的委托使用》介绍了EventHandler的简单使用,本篇主要介绍线程中的AutoResetEvent来实现整个读卡器的操作过程。
视频场景
读卡器操作
微卡智享
与读卡器的对接也是调用的读卡器厂家的动态库,根据读卡器厂家的设备操作流程:
其实从上面的读卡器操作流程来看,也能看出来为什么我们上一篇文章要讲EventHandler了,这样就可以把读卡的逻辑和读到卡数据后的业务逻辑进行分开了。话不多说,正篇开始。
AutoResetEvent简介
微卡智享
AutoResetEvent对象用来进行线程同步操作,AutoResetEvent类继承waitHandle类。waitOne()方法就继承来自waitHandle类。
# | 主要方法 |
---|---|
1 | AutoResetEvent(bool initialState):构造函数,参数false:无信号,子线程的WaitOne方法不会被自动调用 true:有信号,子线程的WaitOne方法会被自动调用 |
2 | Reset ():将事件状态设置为非终止状态,导致线程阻止;如果该操作成功,则返回true;否则,返回false。 |
3 | Set ():将事件状态设置为终止状态,允许一个或多个等待线程继续;如果该操作成功,则返回true;否则,返回false。 |
4 | WaitOne():阻止当前线程,直到收到信号。 |
5 | WaitOne(TimeSpan, Boolean) :阻止当前线程,直到当前实例收到信号,使用 TimeSpan 度量时间间隔并指定是否在等待之前退出同步域。 |
上面就是AutoResetEvent的主要方法,从上面的主要方法中我们可以看到,实现读卡器每100耗秒进行检测,原来通过线程是sleep进行处理,现在可以使用WaitOne的方式,并且通过这个方法,我们可以在外部实现读卡器重连的调用。
本项目场景
本项目(开头视频)中因为读卡器使用的网络通讯,所以我们要考虑出现异常情况下实现读卡器自动重连。
根据上面的情况,我们就可考虑除了读卡数据异常时需要自动重新连接,还要在外部接口中封装一个函数,可以从外部直接调用重连读卡器。实际项目中对读卡器的操作没法贴上来,这里我们就接着一个DEMO,模拟一下这个场景。
代码演示
微卡智享
接着我们的threaddemo,在CTest的类中我们开始改造。
先定义一个AutoResetEvent,和等待的毫秒waitTime。
然后定义一个Reset的方法,模拟读卡器重启。
原来的停止方法中加入isRunning的开关,再调用exitEvent的Reset和Set,这样就可以区分是重启还是终止。
我们在循环的操作里面加入一个随机数生成,取值为0到13内
代码
using System;using System.Collections.Generic;using System.Drawing.Text;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;
namespace threaddemo{ public class CTest : Inftest,IDisposable { public int id;
private AutoResetEvent exitEvent;
private Thread thread;
private int waitTime = 100;
private bool disposed = false;
private bool IsRunning;
public int cs = 0; public CTest(int _id) { id = _id; exitEvent = new AutoResetEvent(false); thread = new Thread(ReadThreadRun); thread.IsBackground = true; }
public event EventHandler<testEvent> DataReceived;
public void Dispose() { // Dispose(true); GC.SuppressFinalize(this); }
protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { try { Stop();
} catch (Exception) {
} } disposed = true; } }
public void Start() { IsRunning = true; thread.Start(); }
public void Stop() { IsRunning = false; exitEvent.Reset(); exitEvent.Set(); RaiseDataReceived("手动停止"); }
public void Reset() { exitEvent.Reset(); exitEvent.Set(); }
public void setcs(int _cs) { cs = _cs;
}
private void RaiseDataReceived(string msg) { DataReceived?.Invoke(this, new testEvent(msg, id)); }
/// <summary> /// 接收线程 /// </summary> private void ReadThreadRun() { while (IsRunning) { try { if (exitEvent.WaitOne(waitTime)) { if (IsRunning) { Thread.Sleep(1000); id++; if (id % 5 == 0) { throw new Exception("余数:0"); }else if (id % 5 == 1) { try { throw new Exception("故意出错"); } catch(Exception ex) { RaiseDataReceived(ex.Message); Reset(); } } RaiseDataReceived("状态:重启"); } else { Thread.Sleep(1000); RaiseDataReceived("停止"); } }
Random rd = new Random(); int count = rd.Next(0, 13); if (count < 10) { RaiseDataReceived(count.ToString()); } else if (count == 10) { throw new Exception("throw 数字:" + count); } else { RaiseDataReceived("数字:" + count + " Reset"); Reset(); } } catch (Exception ex) { RaiseDataReceived("error " + ex.Message); Reset(); }
//Thread.Sleep(100); } } }}
实现效果
https://github.com/Vaccae/EventHandlerDemo.git