学更好的别人,
做更好的自己。
——《微卡智享》
本文长度为3106字,预计阅读8分钟
前言
前一篇《学习|C#的EventHandler的委托使用》介绍了EventHandler的简单使用,本篇主要介绍线程中的AutoResetEvent来实现整个读卡器的操作过程。
视频场景
读卡器操作

微卡智享
与读卡器的对接也是调用的读卡器厂家的动态库,根据读卡器厂家的设备操作流程:
其实从上面的读卡器操作流程来看,也能看出来为什么我们上一篇文章要讲EventHandler了,这样就可以把读卡的逻辑和读到卡数据后的业务逻辑进行分开了。话不多说,正篇开始。
AutoResetEvent简介

微卡智享
AutoResetEvent对象用来进行线程同步操作,AutoResetEvent类继承waitHandle类。waitOne()方法就继承来自waitHandle类。
AutoResetEvent的主要方法
# | 主要方法 |
---|---|
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内
如果取值的数字小于10,那就正常发送数据。
如果取值的数字等于10,那就直接抛出异常,然后在异常中内部模拟Reset重连读卡器。
如果取值的数字大于10,也直接进行重连,只不过不用抛出异常。
代码
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
完
扫描二维码
获取更多精彩
微卡智享
「 往期文章 」