123 lines
3.6 KiB
C#
123 lines
3.6 KiB
C#
|
// /************************************************************************
|
|||
|
// * @file DeviceLocker.cs
|
|||
|
// * @author Su Liang
|
|||
|
// * @date 2022/11/16
|
|||
|
// *
|
|||
|
// * @copyright © Sicentury Inc.
|
|||
|
// *
|
|||
|
// * @brief 设备资源锁定器。
|
|||
|
// *
|
|||
|
// * @details 当某个设备或其它资源不能被多个线程同时使用时,可使用此锁定器实现资源互斥操作。
|
|||
|
// *
|
|||
|
// *
|
|||
|
// * *****************************************************************************/
|
|||
|
|
|||
|
|
|||
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.Threading;
|
|||
|
using MECF.Framework.Common.Equipment;
|
|||
|
|
|||
|
namespace SicRT.Equipments.Systems
|
|||
|
{
|
|||
|
public class DeviceLocker
|
|||
|
{
|
|||
|
private readonly object _syncRoot = new object();
|
|||
|
private readonly SemaphoreSlim _semResource;
|
|||
|
|
|||
|
#region Constructor
|
|||
|
|
|||
|
public DeviceLocker(string deviceName, int maxResCount)
|
|||
|
{
|
|||
|
DeviceName = deviceName;
|
|||
|
_semResource = new SemaphoreSlim(maxResCount, maxResCount);
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Properties
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 设备名称。
|
|||
|
/// </summary>
|
|||
|
public string DeviceName { get; }
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 返回占有该设备的对象名称.
|
|||
|
/// <para>关于可能使用到的占用者名称,请参考枚举类型<see cref="ModuleName"/>。</para>
|
|||
|
/// </summary>
|
|||
|
public List<string> Occupiers { get; private set; }
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region MyRegion
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 锁定设备。
|
|||
|
/// </summary>
|
|||
|
/// <param name="occupier"></param>
|
|||
|
/// <param name="timeoutInMillisecond"></param>
|
|||
|
/// <param name="reason"></param>
|
|||
|
/// <returns></returns>
|
|||
|
public bool Lock(ModuleName occupier, out string reason, int timeoutInMillisecond = 100)
|
|||
|
{
|
|||
|
lock (_syncRoot)
|
|||
|
{
|
|||
|
var a = Occupiers.FirstOrDefault(x => x == occupier.ToString());
|
|||
|
if (a != null)
|
|||
|
{
|
|||
|
reason = $"{DeviceName} had been lock by {occupier}";
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
if (_semResource.Wait(timeoutInMillisecond))
|
|||
|
{
|
|||
|
Occupiers.Add(occupier.ToString());
|
|||
|
reason = "";
|
|||
|
return true;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
reason = $"Unable to lock {DeviceName}, no enough resources, locked by {string.Join(", ", Occupiers)}";
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 释放设备。
|
|||
|
/// </summary>
|
|||
|
/// <param name="occupier"></param>
|
|||
|
/// <param name="reason"></param>
|
|||
|
/// <returns></returns>
|
|||
|
public bool Release(ModuleName occupier, out string reason)
|
|||
|
{
|
|||
|
lock (_syncRoot)
|
|||
|
{
|
|||
|
var a = Occupiers.FirstOrDefault(x => x == occupier.ToString());
|
|||
|
if (a == null)
|
|||
|
{
|
|||
|
reason = $"{DeviceName} is never locked by {occupier}";
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
_semResource.Release(1);
|
|||
|
Occupiers.Remove(occupier.ToString());
|
|||
|
reason = "";
|
|||
|
return true;
|
|||
|
}
|
|||
|
catch (Exception ex)
|
|||
|
{
|
|||
|
reason = $"Unable to lock {DeviceName} by {occupier}, {ex.Message}";
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
}
|
|||
|
}
|