/// <summary>
/// 其他混合锁
/// </summary>
internal sealed class AnotherHybridLock : IDisposable
{
//由基元用户模式构造(Interlocked的方法)使用
private int _waiters = 0;
//AutoResetEvent 是基元内核模式构造
private AutoResetEvent _waiterLock = new AutoResetEvent(false);
//这个字段控制自旋,希望提升性能
private int _spinCount = 4000; //随便选择的一个计数
//这些字段指出哪个线程拥有锁,以及拥有了它多少次
private int _owingThreadId = 0, _recursion = 0;
public void Enter()
{
//如果调用线程已经拥有锁,递增递归计数并返回
int threadId = Thread.CurrentThread.ManagedThreadId;
if (threadId == _owingThreadId)
{
_recursion++;
return;
}
//调用的线程不再拥有锁,尝试获取它
SpinWait spinwait = new SpinWait();
for (int i = 0; i < _spinCount; i++)
{
//如果锁可以自由使用了,这个线程就获得它:设置一些状态并返回
if (Interlocked.CompareExchange(ref _waiters, 1, 0) == 0)
goto GotLock;
//黑科技:给其他线程运行的机会,希望锁会被释放
spinwait.SpinOnce();
}
//自旋结束,锁仍未获得,再试一次
if (Interlocked.Increment(ref _waiters) > 1)
{
//仍然是竞态条件,这个线程必须阻塞
_waiterLock.WaitOne(); //等待锁:性能有损失
//等待这个线程醒来时,它拥有锁:设置一些状态并返回
}
GotLock:
//一个线程获得锁时,我们记录它的ID,并指出线程拥有锁一次
_owingThreadId = threadId;
_recursion = 1;
}
public void Leave()
{
//如果调用线程不再拥有锁,表明存在bug
int threadId = Thread.CurrentThread.ManagedThreadId;
if (threadId != _owingThreadId)
throw new SynchronizationLockException("Lock not owned by calling thread");
//递减递归计数。如果这个线程仍然拥有锁,那么直接返回
if (--_recursion > 0)
return;
_owingThreadId = 0; //现在没有线程拥有锁
//如果没有其他线程在等待,直接返回
if (Interlocked.Decrement(ref _waiters) == 0)
return;
//有其他线程正在阻塞,唤醒其中一个
_waiterLock.Set(); //这里产生较大的性能影响
}
public void Dispose()
{
_waiterLock.Dispose();
}
}