网上演练
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.

233 lines
7.2 KiB

#if FAT
using System;
using System.Threading;
namespace LinqInternal.Threading
{
internal sealed partial class NoReentrantReadWriteLock : IReadWriteLock
{
private int _edge;
private ManualResetEventSlim _freeToRead = new ManualResetEventSlim(false); // Disposed
private ManualResetEventSlim _freeToWrite = new ManualResetEventSlim(false); // Disposed
private int _master;
private Thread _ownerThread;
private int _readCount;
private int _writeCount;
public bool HasReader
{
get { return _readCount > 0; }
}
public bool HasWriter
{
get { return _ownerThread != null; }
}
public bool IsCurrentThreadReader
{
get { throw new NotSupportedException("Only a ReentratReadWriteLock keeps tracks of which thread is a reader."); }
}
public bool IsCurrentThreadWriter
{
get { return Thread.CurrentThread == _ownerThread; }
}
public IDisposable EnterRead()
{
WaitCanRead();
return DisposableAkin.Create(DoneRead);
}
public IDisposable EnterWrite()
{
WaitCanWrite();
return DisposableAkin.Create(DoneWrite);
}
public bool TryEnterRead(out IDisposable engagement)
{
engagement = null;
if (!CanRead())
{
return false;
}
engagement = DisposableAkin.Create(DoneRead);
return true;
}
public bool TryEnterWrite(out IDisposable engagement)
{
engagement = null;
if (!CanWrite())
{
return false;
}
engagement = DisposableAkin.Create(DoneWrite);
return true;
}
private bool CanRead()
{
if (Thread.CurrentThread == Volatile.Read(ref _ownerThread))
{
Interlocked.Increment(ref _readCount);
return true;
}
else
{
if (Interlocked.CompareExchange(ref _master, 1, 0) >= 0)
{
_freeToWrite.Reset();
Interlocked.Increment(ref _readCount);
return true;
}
return false;
}
}
private bool CanWrite()
{
if (Thread.CurrentThread == Volatile.Read(ref _ownerThread))
{
Interlocked.Increment(ref _writeCount);
return true;
}
else
{
if (Interlocked.CompareExchange(ref _master, -1, 0) == 0)
{
_freeToRead.Reset();
if (Interlocked.CompareExchange(ref _ownerThread, Thread.CurrentThread, null) == null)
{
// Success
Interlocked.Increment(ref _writeCount);
return true;
}
}
return false;
}
}
private void DoneRead()
{
if (Thread.CurrentThread == Volatile.Read(ref _ownerThread))
{
Interlocked.Decrement(ref _readCount);
}
else
{
if (Volatile.Read(ref _master) < 0)
{
if (Interlocked.Decrement(ref _readCount) <= Volatile.Read(ref _edge))
{
Volatile.Write(ref _master, 0);
_freeToWrite.Set();
}
}
else
{
Interlocked.Decrement(ref _readCount);
}
}
}
private void DoneWrite()
{
if (Interlocked.Decrement(ref _writeCount) == 0)
{
Volatile.Write(ref _master, 0);
Volatile.Write(ref _ownerThread, null);
_freeToRead.Set();
_freeToWrite.Set();
}
}
private void WaitCanRead()
{
if (Thread.CurrentThread != Volatile.Read(ref _ownerThread))
{
var check = Interlocked.CompareExchange(ref _master, 1, 0);
while (true)
{
switch (check)
{
case -2:
// Write mode already requested
case -1:
// There is a writer
// Go to wait
_freeToRead.Wait();
check = Interlocked.CompareExchange(ref _master, 1, 0);
break;
case 0:
// Free to proceed
// GO!
_freeToWrite.Reset();
goto case 1;
case 1:
// There are readers currently
// GO!
Interlocked.Increment(ref _readCount);
return;
}
}
}
}
private void WaitCanWrite()
{
if (Thread.CurrentThread != Volatile.Read(ref _ownerThread))
{
var check = Interlocked.CompareExchange(ref _master, -1, 0);
while (true)
{
switch (check)
{
case -2:
// Write mode already requested
case -1:
// There is another writer
// Go to wait
_freeToWrite.Wait();
check = Interlocked.CompareExchange(ref _master, -1, 0);
break;
case 0:
// Free to proceed
// GO!
_freeToRead.Reset();
if (Interlocked.CompareExchange(ref _ownerThread, Thread.CurrentThread, null) == null)
{
// Success
Interlocked.Increment(ref _writeCount);
return;
}
else
{
// It was reserved by another thread
break;
}
case 1:
// There are readers currently
// Requesting write mode
check = Interlocked.CompareExchange(ref _master, -2, 1);
if (check == 1)
{
_freeToRead.Reset();
check = -2;
}
break;
}
}
}
}
}
}
#endif