141 lines
4.0 KiB
C#
141 lines
4.0 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;
|
|
|
|
namespace Sicentury.Core
|
|
{
|
|
public class DeviceLocker
|
|
{
|
|
public enum Results
|
|
{
|
|
Ok,
|
|
Error,
|
|
IHaveLocker
|
|
}
|
|
|
|
private readonly object _syncRoot = new object();
|
|
|
|
/// <summary>
|
|
/// 返回占有该设备的对象名称.
|
|
/// <para>关于可能使用到的占用者名称,请参考枚举类型<see cref="ModuleName"/>。</para>
|
|
/// </summary>
|
|
private readonly List<string> _occupiersCollection;
|
|
private SemaphoreSlim _semResource;
|
|
private readonly int _maxRes;
|
|
|
|
#region Constructor
|
|
|
|
public DeviceLocker(string lockerName, int maxResCount)
|
|
{
|
|
LockerName = lockerName;
|
|
_occupiersCollection = new List<string>();
|
|
_maxRes = maxResCount;
|
|
_semResource = new SemaphoreSlim(maxResCount, maxResCount);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
/// <summary>
|
|
/// 设备名称。
|
|
/// </summary>
|
|
public string LockerName { get; }
|
|
|
|
#endregion
|
|
|
|
#region MyRegion
|
|
|
|
/// <summary>
|
|
/// 锁定设备。
|
|
/// </summary>
|
|
/// <param name="occupier"></param>
|
|
/// <param name="timeoutInMillisecond"></param>
|
|
/// <param name="reason"></param>
|
|
/// <returns></returns>
|
|
public Results TryLock(string occupier, out string reason, int timeoutInMillisecond)
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
var a = _occupiersCollection.FirstOrDefault(x => x == occupier.ToString());
|
|
if (a != null)
|
|
{
|
|
reason = $"{LockerName} had been lock by {occupier}";
|
|
return Results.IHaveLocker;
|
|
}
|
|
}
|
|
|
|
if (_semResource.Wait(timeoutInMillisecond))
|
|
{
|
|
_occupiersCollection.Add(occupier);
|
|
reason = "";
|
|
return Results.Ok;
|
|
}
|
|
else
|
|
{
|
|
reason =
|
|
$"Unable to lock {LockerName}, no enough resources, locked by {string.Join(", ", _occupiersCollection)}";
|
|
return Results.Error;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 释放设备。
|
|
/// </summary>
|
|
/// <param name="occupier"></param>
|
|
/// <param name="reason"></param>
|
|
/// <returns></returns>
|
|
public Results TryUnlock(string occupier, out string reason)
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
var a = _occupiersCollection.FirstOrDefault(x => x == occupier);
|
|
if (a == null)
|
|
{
|
|
reason = $"{LockerName} is never locked by {occupier}";
|
|
return Results.Error;
|
|
}
|
|
|
|
try
|
|
{
|
|
_semResource.Release(1);
|
|
_occupiersCollection.Remove(occupier);
|
|
reason = "";
|
|
return Results.Ok;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
reason = $"Unable to lock {LockerName} by {occupier}, {ex.Message}";
|
|
return Results.Error;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
_semResource = new SemaphoreSlim(_maxRes, _maxRes);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
} |