网上演练
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123 lines
3.5 KiB

#if FAT
using System.Threading;
using LinqInternal.Collections.Specialized;
using LinqInternal.Collections.ThreadSafe;
using LinqInternal.Core;
using LinqInternal.Threading.Needles;
namespace LinqInternal.Threading
{
internal class LockContext<T>
{
private readonly FixedSizeQueue<LockSlot<T>> _closedSlots;
private readonly NeedleBucket<LockSlot<T>, LazyNeedle<LockSlot<T>>> _slots;
private readonly VersionProvider _version = new VersionProvider();
private int _index;
private readonly int _capacity;
public LockContext(int capacity)
{
_capacity = NumericHelper.PopulationCount(capacity) == 1 ? capacity : NumericHelper.NextPowerOf2(capacity);
_slots = new NeedleBucket<LockSlot<T>, LazyNeedle<LockSlot<T>>>
(
index => new LockSlot<T>
(
this,
index,
_version.AdvanceNewToken()
),
key => new LazyNeedle<LockSlot<T>>(key),
_capacity
);
_closedSlots = new FixedSizeQueue<LockSlot<T>>(_capacity);
}
internal int Capacity
{
get { return _capacity; }
}
internal bool ClaimSlot(out LockSlot<T> slot)
{
if (TryClaimFreeSlot(out slot))
{
return true;
}
if (_slots.Count < _slots.Capacity)
{
var index = Interlocked.Increment(ref _index) & (_capacity - 1);
slot = _slots.Get(index);
return true;
}
slot = null;
return false;
}
internal void Close(LockSlot<T> slot)
{
_closedSlots.Add(slot);
}
internal bool Read(FlagArray flags, ref int owner, out LockSlot<T> slot)
{
if (Read(ref owner, out slot))
{
return true;
}
var resultLock = -1;
foreach (var flag in flags.Flags)
{
LockSlot<T> testSlot;
if (!_slots.TryGet(flag, out testSlot))
{
continue;
}
if (slot == null || slot.CompareTo(testSlot) < 0)
{
slot = testSlot;
resultLock = flag;
}
}
if (Interlocked.CompareExchange(ref owner, resultLock, -1) != -1)
{
return Read(ref owner, out slot);
}
if (slot == null)
{
return false;
}
return true;
}
private bool Read(ref int owner, out LockSlot<T> slot)
{
slot = null;
var got = owner;
if (got == -1)
{
return false;
}
LockSlot<T> found;
if (_slots.TryGet(got, out found) && found.IsOpen)
{
slot = found;
return true;
}
Interlocked.CompareExchange(ref owner, -1, got);
return false;
}
private bool TryClaimFreeSlot(out LockSlot<T> slot)
{
if (_closedSlots.TryTake(out slot))
{
slot.Open(_version.AdvanceNewToken());
return true;
}
return false;
}
}
}
#endif