Sic04/SicRT/Equipments/Systems/DeviceLocker.cs

123 lines
3.6 KiB
C#
Raw Normal View History

// /************************************************************************
// * @file DeviceLocker.cs
// * @author Su Liang
// * @date 2022/11/16
// *
// * @copyright &copy 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
}
}