假设我想实现一个同步原语,它生成一个将在同步协议中使用的时间戳。时间戳是这样的,对于用于锁定资源的给定键,没有两个线程能够获得相同的时间戳值。
后一种规范的可能实现是:
namespace InfinityLabs.PowersInfinity.BCL.Synchronization
{
public static class TimeStampMonitor
{
private static readonly IDictionary<object, long> TimeStamps;
static TimeStampMonitor()
{
TimeStamps = new Dictionary<object, long>();
}
#region API
public static long Enter(object key)
{
var lockTaken = false;
Monitor.Enter(key, ref lockTaken);
ThrowIfLockNotAcquired(key, lockTaken);
var timeStamp = GetCurrentTimeStamp();
Thread.Sleep(1);
TimeStamps.Add(key, timeStamp);
return timeStamp;
}
public static void Exit(object key)
{
var lockTaken = false;
Monitor.Enter(key, ref lockTaken);
try
{
ThrowIfInvalidKey(key);
TimeStamps.Remove(key);
}
finally
{
if (lockTaken)
Monitor.Exit(key);
}
}
public static long GetTimeStampOrThrow(object key)
{
TryEnterOrThrow(key);
var timeStamp = GetTimeStamp(key);
return timeStamp;
}
public static void TryEnterOrThrow(object key)
{
var lockTaken = false;
try
{
Monitor.Enter(key, ref lockTaken);
ThrowIfLockNotAcquired(key, lockTaken);
ThrowIfInvalidKey(key);
}
catch (SynchronizationException)
{
throw;
}
catch (Exception)
{
if(lockTaken)
Monitor.Exit(key);
throw;
}
}
#endregion
#region Time Stamping
private static long GetCurrentTimeStamp()
{
var timeStamp = DateTime.Now.ToUnixTime();
return timeStamp;
}
private static long GetTimeStamp(object key)
{
var timeStamp = TimeStamps[key];
return timeStamp;
}
#endregion
#region Validation
private static void ThrowIfInvalidKey(object key, [CallerMemberName] string methodName = null)
{
if (!TimeStamps.ContainsKey(key))
throw new InvalidOperationException($"Must invoke '{nameof(Enter)}' prior to invoking '{methodName}'. Key: '{key}'");
}
private static void ThrowIfLockNotAcquired(object key, bool lockTaken)
{
if (!lockTaken)
throw new SynchronizationException($"Unable to acquire lock for key '{key}'");
}
#endregion
}
}
请注意,TryEnterOrThrow和GetTimeStampOrThrow这两个 API 方法旨在通过使用类作为保护方法来使用,这些方法不允许编写不佳的代码破坏临界区的原子性。后一种方法还返回给定键的先前获取的时间戳值。时间戳保持如此之久,以至于其所有者没有退出关键部分。
我一直在脑海中运行所有可能的场景,但我似乎无法打破它——不仅是原子的,而是试图滥用它。我想我的问题是,因为这是我编写同步原语的极少数尝试之一——这段代码是万无一失的吗?它是否提供原子性?
帮助将不胜感激!