设备驱动管理器的设计

2019-10-08 15:34 来源:未知

目       录

第四章           设备驱动管理器的设计... 2

4.1           接口定义... 2

4.2           设备容器... 7

4.3           生成设备ID.. 7

4.4           对配备容器操作的互斥... 8

4.5           获得器具列表... 8

4.6           设备计数器的超过常规规用处... 8

4.7           小结... 10

 

第四章     设备驱动管理器的设计

    设备驱动处理器是对IRunDevice设备驱动接口的管制,是框架首要的组成都部队分之一。不管设备驱动管理器怎么规划、以什么形式存在,在概念上必然是存在的。设计好的设备驱动管理器对于框架平台的稳固性运转入眼。

   在介绍道具驱动处理器从前,先简要介绍一下IO调整器(IIOController),它最主要担当对IO和设施实行调解,并驱动装置运维,在《第5章 串口和网络的IO设计》实行详细的介绍。也正是说二个IO调控器只怕会对应多少个设施驱动(插件)。

   开始的一段时代的时候,每一个IO调控器都有多少个设施驱动管理器。在框架平台运转的时候,依照设备驱动的通信参数把相应的装置驱动分配到相应的IO管理器;当IO参数发生变化的时候,会触发事件,把该设备驱动从脚下IO调控器移动到另四个IO调整器。

   从事情角度来思虑,那样做并未怎么难点,何况直接运行的很平静。可是,从模块化、扩大性角度来考虑,不是太雅观,假使在别的省方调用某八个设施驱动时,不能够平素、非常快的找到该设备驱动,供给遍历IO调控器再合作相应的装置驱动,而且操作麻烦以及效用不高。

   在对框架平台扩充重构的时候,把该难题举行了重新思念,并把相关联的主题素材一齐消除。把每一种IO调整器中的设备驱动处理器实行了整合,用贰个设备驱动管理器来实现框架平台的调弄整监护人业。

   那块涉及到的手艺并简单,也很轻巧掌握,不过在规划进度中须要在意一些细节难点,这么些标题或然影响框架平台的安居。

4.1    接口定义

    先定义一个接口(IDeviceManager<TKey, 电视机alue>),明确设备驱动处理器都要落成什么功用,扩张设备、删除设备、获得器械和列表、以及别的的效劳。接口代码如下:

public interface IDeviceManager<TKey, TValue> : IEnumerable<TValue> where TValue : IRunDevice
{
       /// <summary>
       /// 新建设备的ID,且唯一
       /// </summary>
       /// <returns></returns>
       string BuildDeviceID();

       /// <summary>
       /// 增加设备
       /// </summary>
       /// <param name="key"></param>
       /// <param name="val"></param>
       void AddDevice(TKey key, TValue val);

       /// <summary>
       /// 删除设备
       /// </summary>
       /// <param name="key"></param>
       void RemoveDevice(TKey key);

       /// <summary>
       /// 移除所有设备
       /// </summary>
       void RemoveAllDevice();

       /// <summary>
       /// 获得值集合
       /// </summary>
       /// <returns></returns>
       List<TValue> GetValues();

       /// <summary>
       /// 获得关键字集合
       /// </summary>
       /// <returns></returns>
       List<TKey> GetKeys();

       /// <summary>
       /// 获得设备的ID和名称
       /// </summary>
       /// <returns></returns>
       Dictionary<int, string> GetDeviceIDAndName();

       /// <summary>
       /// 获得高优先运行设备
       /// </summary>
       /// <param name="vals"></param>
       /// <returns></returns>
       TValue GetPriorityDevice(TValue[] vals);

       /// <summary>
       /// 获得单个设备
       /// </summary>
       /// <param name="key"></param>
       /// <returns></returns>
       TValue GetDevice(TKey key);

       /// <summary>
       /// 获得设备数组
       /// </summary>
       /// <param name="para">IP或串口号</param>
       /// <param name="ioType">通讯类型</param>
       /// <returns></returns>
       TValue[] GetDevices(string para, CommunicationType ioType);

       /// <summary>
       /// 获得指定IP和工作模式的网络设备
       /// </summary>
       /// <param name="remoteIP"></param>
       /// <param name="workMode"></param>
       /// <returns></returns>
       TValue[] GetDevices(string remoteIP, WorkMode workMode);

       /// <summary>
       /// 获得指定工作模式的网络设备
       /// </summary>
       /// <param name="workMode"></param>
       /// <returns></returns>
       TValue[] GetDevices(WorkMode workMode);

       /// <summary>
       /// 获得设备数组
       /// </summary>
       /// <param name="ioType"></param>
       /// <returns></returns>
       TValue[] GetDevices(CommunicationType ioType);

       /// <summary>
       /// 按设备类型获得设备
       /// </summary>
       /// <param name="devType"></param>
       /// <returns></returns>
       TValue[] GetDevices(Device.DeviceType devType);

       /// <summary>
       /// 判断设备是否存在
       /// </summary>
       /// <param name="key"></param>
       /// <returns></returns>
       bool ContainDevice(TKey key);

       /// <summary>
       /// 根据输入参数,判断是否包括设备
       /// </summary>
       /// <param name="para">IP或串口号</param>
       /// <param name="ioType">设备通讯类型</param>
       /// <returns></returns>
       bool ContainDevice(string para, CommunicationType ioType);

       /// <summary>
       /// 设置用户级别
       /// </summary>
       /// <param name="userlevel"></param>
       void SetUserLevel(UserLevel userlevel);

       /// <summary>
      /// 设置是否注册
       /// </summary>
       /// <param name="isreg"></param>
       void SetIsRegLicense(bool isreg);

       /// <summary>
       /// 获得可用设备数
       /// </summary>
       int Count { get; }

       /// <summary>
       /// 获得设备的计数器的值
       /// </summary>
       /// <param name="key"></param>
       ///<returns></returns>
       int GetCounter(TKey key);

       /// <summary>
       /// 设置计数器的值
       /// </summary>
       /// <param name="key"></param>
       /// <param name="val"></param>
       void SetCounter(TKey key, int val);
}

 4.2    设备容器

   设备驱动管理器是对Dictionary<Key,Value>的包裹,Key是器材驱动的ID,Value是IRunDevice设备驱动接口。设备驱动管理器需求跨线程应用,所以对Dictionary操作要加线程同步锁。

   那时采纳的是.NET Framework 2.0框架,没有ConcurrentDictionary(Of TKey, TValue)字典类,那么些类的具备公共和受保证的分子都以线程安全的,使用原子性操作,相符几个线程之间同一时间采取。再重构时可以采取ConcurrentDictionary类替代Dictionary类,因为ConcurrentDictionary的具有操作使用到了Monitor线程同步类,不需求团结再开展打包。

   不贴ConcurrentDictionary类的源代码了,具体运用仿效MSDN。

4.3    生成设备ID

    查寻设备驱动管理器中最大的设施ID,并在此基础上加1。那块代码很简短,

如下:

public string BuildDeviceID()
{
       if(_dic.Count>0)
       {
          int maxID=_dic.Max(d => d.Value.DeviceParameter.DeviceID);
          return (++maxID);
       }
       else
       {
              return 0;
       }
}

    扩大设备驱动是内需转换设备ID,日常选择手动增添设备驱动,所以在那块无需加线程同步锁。

4.4    对设备容器操作的排斥

框架平台具有组件要共享设备驱动管理器,所以会涉及到跨线程应用,极其

是当集结产生变动的时候,大概会现身万分。比方:运营框架平台的时候,IO调整器已经运营,IO调控器从设备驱动管理器提取本身的设备列表,不过此时有大概还并未有加载完设备驱动,当有新的配备驱动扩充到设备驱动管理时,或许会引发争执。

    所以,在加码设备、删除设备和获取道具列表的时候扩张了线程同步锁,比方:lock (_SyncLock)。

4.5    获得器材列表

有多少个获得装备的构造函数(GetDevices),主借使知足分裂的选取场景。

澳门国际银河备用网址,请参谋“4.1接口定义”。

    其它,获得高优先运维设备的GetPriorityDevice函数在上一章节曾经介绍了。

4.6    设备计数器的特有用途

    在接口定义中有SetCounter和GetCounter五个函数,用在电视发表进程中。

    应用场景是这么的,在现身和平协议束通信格局中,设备驱动平素处在在简报不奇怪的意况下,然则陡然发生线路中断或其余原因导致望眼欲穿吸收接纳到数码时,那么设备驱动一直不只怕吸取到多少,也无从对广播发表状态举行检查实验以及改变相应的多寡音信,也正是说现真实景况况已经爆发改动,然而设备驱动却无力回天获得响应。

    为了防御这种场地包车型地铁产出,设备驱动每一趟发送数据时,通过GetCounter函数得到当前器材驱动的计数器,对计数器(变量)+1操作,并由此SetCounter函数把计数器(变量)再写到设备驱动管理器中。在老大接收数据的时候,实行同一的流程,但是进行-1操作。要是直接发送数据,而并未有接受到数码时,当前设施驱动的计数器就能够直接在加上。假诺过量等于有个别值的时候,就能够经过RunIODevice(new byte[]{})驱动当前设施,推行总体设施管理流程,一回开辟的代码块就能够被调用,来变成此类应用场景的情事改变和数量变化。代码如下:

int counter = DeviceManager.GetInstance().GetCounter(dev.DeviceParameter.DeviceID.ToString());
int sendNum = SessionSocketManager.GetInstance().Send(dev.DeviceParameter.NET.RemoteIP, data);
if (sendNum == data.Length && sendNum != 0)
{
       DeviceMonitorLog.WriteLog(dev.DeviceParameter.DeviceName, "发送请求数据");
       Interlocked.Increment(ref counter);
}
else
{
       Interlocked.Increment(ref counter);
       DeviceMonitorLog.WriteLog(dev.DeviceParameter.DeviceName, "尝试发送数据失败");
}
dev.ShowMonitorIOData(data, "发送");
if (counter >= 3)
{
       try
       {
              dev.RunIODevice(new byte[] { });
       }
       catch (Exception ex)
       {
              DeviceMonitorLog.WriteLog(dev.DeviceParameter.DeviceName, ex.Message);
              GeneralLog.WriteLog(ex);
       }
       Interlocked.Exchange(ref counter, 0);
}
DeviceManager.GetInstance().SetCounter(dev.DeviceParameter.DeviceID.ToString(), counter);

   对于发送和接受数据会在不一样的线程上做到,在对计数器(变量)进行+1和-1操作的时候利用到了Interlocked类,用于四个线程分享的变量提供原子操作,幸免在多管理器上并行操作时大概引发的不得了或数额遭到破坏。

4.7    小结

   那样退换后,既能够在IO调控器对设备实行援用,也能够在别的零件使用。假若蒙受类似的状态,希望利用ConcurrentDictionary类。

 

作者:唯笑志在

Email:504547114@qq.com

QQ:504547114

.NET开垦技艺缔盟:54256083

文书档案下载:

合法国网球限制赛址:http://www.bmpj.net

TAG标签:
版权声明:本文由澳门国际银河备用网址发布于澳门国际银河备用网址,转载请注明出处:设备驱动管理器的设计