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

264 lines
6.8 KiB

#if NET20 || NET30 || NET35 || !NET_4_6
using System.Diagnostics;
using LinqInternal.Threading;
namespace System.Threading
{
[DebuggerDisplay("Initial Count={InitialCount}, Current Count={CurrentCount}")]
public class CountdownEvent : IDisposable
{
private readonly ManualResetEventSlim _event;
private int _currentCount;
private volatile bool _disposed;
private int _initialCount;
public CountdownEvent(int initialCount)
{
if (initialCount < 0)
{
throw new ArgumentOutOfRangeException("initialCount");
}
else
{
_initialCount = initialCount;
_currentCount = initialCount;
_event = new ManualResetEventSlim();
if (initialCount == 0)
{
_event.Set();
}
}
}
public int CurrentCount
{
get
{
var currentCount = Thread.VolatileRead(ref _currentCount);
return currentCount >= 0 ? currentCount : 0;
}
}
public int InitialCount
{
get { return _initialCount; }
}
public bool IsSet
{
get { return Thread.VolatileRead(ref _currentCount) <= 0; }
}
public WaitHandle WaitHandle
{
get
{
CheckDisposed();
return _event.WaitHandle;
}
}
public void AddCount()
{
AddCount(1);
}
public void AddCount(int signalCount)
{
if (!TryAddCount(signalCount))
{
throw new InvalidOperationException("Already Zero");
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Reset()
{
Reset(_initialCount);
}
public void Reset(int count)
{
CheckDisposed();
if (count < 0)
{
throw new ArgumentOutOfRangeException("count");
}
else
{
Thread.VolatileWrite(ref _currentCount, count);
_initialCount = count;
if (count == 0)
{
_event.Set();
}
else
{
_event.Reset();
}
}
}
public bool Signal()
{
CheckDisposed();
if (Thread.VolatileRead(ref _currentCount) <= 0)
{
throw new InvalidOperationException("Below Zero");
}
else
{
var currentCount = Interlocked.Decrement(ref _currentCount);
if (currentCount == 0)
{
_event.Set();
return true;
}
else
{
if (currentCount < 0)
{
throw new InvalidOperationException("Below Zero");
}
else
{
return false;
}
}
}
}
public bool Signal(int signalCount)
{
if (signalCount <= 0)
{
throw new ArgumentOutOfRangeException("signalCount");
}
else
{
CheckDisposed();
int lastValue;
if (ThreadingHelper.SpinWaitRelativeExchangeUnlessNegative(ref _currentCount, -signalCount, out lastValue))
{
var result = lastValue - signalCount;
if (result == 0)
{
_event.Set();
return true;
}
else
{
return false;
}
}
else
{
throw new InvalidOperationException("Below Zero");
}
}
}
public bool TryAddCount()
{
return TryAddCount(1);
}
public bool TryAddCount(int signalCount)
{
if (signalCount <= 0)
{
throw new ArgumentOutOfRangeException("signalCount");
}
else
{
CheckDisposed();
int lastValue;
if (ThreadingHelper.SpinWaitRelativeExchangeBounded(ref _currentCount, signalCount, 1, int.MaxValue, out lastValue))
{
return true;
}
else
{
if (lastValue < 1)
{
return false;
}
else
{
throw new InvalidOperationException("Max");
}
}
}
}
public void Wait()
{
Wait(-1, CancellationToken.None);
}
public void Wait(CancellationToken cancellationToken)
{
Wait(-1, cancellationToken);
}
public bool Wait(TimeSpan timeout)
{
var totalMilliseconds = (long)timeout.TotalMilliseconds;
if (totalMilliseconds < -1L || totalMilliseconds > int.MaxValue)
{
throw new ArgumentOutOfRangeException("timeout");
}
else
{
return Wait((int)totalMilliseconds, CancellationToken.None);
}
}
public bool Wait(TimeSpan timeout, CancellationToken cancellationToken)
{
CheckDisposed();
cancellationToken.ThrowIfCancellationRequested();
var isSet = IsSet;
if (!isSet)
{
isSet = _event.Wait(timeout, cancellationToken);
}
return isSet;
}
public bool Wait(int millisecondsTimeout)
{
return Wait(millisecondsTimeout, CancellationToken.None);
}
public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
{
return Wait(TimeSpan.FromMilliseconds(millisecondsTimeout), cancellationToken);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_event.Dispose();
_disposed = true;
}
}
private void CheckDisposed()
{
if (_disposed)
{
throw new ObjectDisposedException("CountdownEvent");
}
}
}
}
#endif