11 [DebuggerDisplay(
"Current Count = {m_currentCount}")]
12 [__DynamicallyInvokable]
13 [HostProtection(
SecurityAction.LinkDemand, Synchronization =
true, ExternalThreading =
true)]
16 private sealed
class TaskNode :
Task<bool>, IThreadPoolWorkItem
18 internal TaskNode Prev;
20 internal TaskNode Next;
27 void IThreadPoolWorkItem.ExecuteWorkItem()
29 bool flag = TrySetResult(result:
true);
38 private volatile int m_currentCount;
40 private readonly
int m_maxCount;
42 private volatile int m_waitCount;
44 private object m_lockObj;
48 private TaskNode m_asyncHead;
50 private TaskNode m_asyncTail;
54 private const int NO_MAXIMUM =
int.MaxValue;
56 private static Action<object> s_cancellationTokenCanceledEventHandler = CancellationTokenCanceledEventHandler;
60 [__DynamicallyInvokable]
63 [__DynamicallyInvokable]
66 return m_currentCount;
73 [__DynamicallyInvokable]
76 [__DynamicallyInvokable]
80 if (m_waitHandle !=
null)
86 if (m_waitHandle ==
null)
99 [__DynamicallyInvokable]
101 : this(initialCount, int.MaxValue)
110 [__DynamicallyInvokable]
113 if (initialCount < 0 || initialCount > maxCount)
121 m_maxCount = maxCount;
122 m_lockObj =
new object();
123 m_currentCount = initialCount;
128 [__DynamicallyInvokable]
139 [__DynamicallyInvokable]
142 Wait(-1, cancellationToken);
152 [__DynamicallyInvokable]
156 if (num < -1 || num >
int.MaxValue)
175 [__DynamicallyInvokable]
179 if (num < -1 || num >
int.MaxValue)
192 [__DynamicallyInvokable]
193 public bool Wait(
int millisecondsTimeout)
208 [__DynamicallyInvokable]
212 if (millisecondsTimeout < -1)
214 throw new ArgumentOutOfRangeException(
"totalMilliSeconds", millisecondsTimeout, GetResourceString(
"SemaphoreSlim_Wait_TimeoutWrong"));
218 if (millisecondsTimeout != -1 && millisecondsTimeout > 0)
220 startTime = TimeoutHelper.GetTime();
224 bool lockTaken =
false;
225 CancellationTokenRegistration cancellationTokenRegistration = cancellationToken.InternalRegisterWithoutEC(s_cancellationTokenCanceledEventHandler,
this);
244 if (m_asyncHead !=
null)
246 task =
WaitAsync(millisecondsTimeout, cancellationToken);
251 if (m_currentCount == 0)
253 if (millisecondsTimeout == 0)
259 flag = WaitUntilCountOrTimeout(millisecondsTimeout, startTime, cancellationToken);
266 if (m_currentCount > 0)
275 if (m_waitHandle !=
null && m_currentCount == 0)
277 m_waitHandle.
Reset();
288 cancellationTokenRegistration.
Dispose();
290 return task?.
GetAwaiter().GetResult() ?? flag;
293 private bool WaitUntilCountOrTimeout(
int millisecondsTimeout, uint startTime,
CancellationToken cancellationToken)
296 while (m_currentCount == 0)
299 if (millisecondsTimeout != -1)
301 num = TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout);
307 if (!Monitor.Wait(m_lockObj, num))
317 [__DynamicallyInvokable]
329 [__DynamicallyInvokable]
341 [__DynamicallyInvokable]
353 [__DynamicallyInvokable]
367 [__DynamicallyInvokable]
371 if (num < -1 || num >
int.MaxValue)
387 [__DynamicallyInvokable]
391 if (millisecondsTimeout < -1)
393 throw new ArgumentOutOfRangeException(
"totalMilliSeconds", millisecondsTimeout, GetResourceString(
"SemaphoreSlim_Wait_TimeoutWrong"));
397 return Task.FromCancellation<
bool>(cancellationToken);
401 if (m_currentCount > 0)
404 if (m_waitHandle !=
null && m_currentCount == 0)
406 m_waitHandle.
Reset();
410 TaskNode taskNode = CreateAndAddAsyncWaiter();
411 return (millisecondsTimeout == -1 && !cancellationToken.
CanBeCanceled) ? taskNode : WaitUntilCountOrTimeoutAsync(taskNode, millisecondsTimeout, cancellationToken);
415 private TaskNode CreateAndAddAsyncWaiter()
417 TaskNode taskNode =
new TaskNode();
418 if (m_asyncHead ==
null)
420 m_asyncHead = taskNode;
421 m_asyncTail = taskNode;
425 m_asyncTail.Next = taskNode;
426 taskNode.Prev = m_asyncTail;
427 m_asyncTail = taskNode;
432 private bool RemoveAsyncWaiter(TaskNode task)
434 bool result = m_asyncHead == task || task.Prev !=
null;
435 if (task.Next !=
null)
437 task.Next.Prev = task.Prev;
439 if (task.Prev !=
null)
441 task.Prev.Next = task.Next;
443 if (m_asyncHead == task)
445 m_asyncHead = task.Next;
447 if (m_asyncTail == task)
449 m_asyncTail = task.Prev;
451 task.Next = (task.Prev =
null);
455 private async
Task<bool> WaitUntilCountOrTimeoutAsync(TaskNode asyncWaiter,
int millisecondsTimeout, CancellationToken cancellationToken)
457 using (CancellationTokenSource cts = cancellationToken.CanBeCanceled ? CancellationTokenSource.CreateLinkedTokenSource(cancellationToken,
default(CancellationToken)) :
new CancellationTokenSource())
460 if (asyncWaiter == await task.
ConfigureAwait(continueOnCapturedContext:
false))
468 if (RemoveAsyncWaiter(asyncWaiter))
470 cancellationToken.ThrowIfCancellationRequested();
474 return await asyncWaiter.ConfigureAwait(continueOnCapturedContext:
false);
481 [__DynamicallyInvokable]
494 [__DynamicallyInvokable]
498 if (releaseCount < 1)
504 int currentCount = m_currentCount;
505 int num = currentCount;
506 if (m_maxCount - currentCount < releaseCount)
510 currentCount += releaseCount;
511 int waitCount = m_waitCount;
512 if (currentCount == 1 || waitCount == 1)
516 else if (waitCount > 1)
520 if (m_asyncHead !=
null)
522 int num2 = currentCount - waitCount;
523 while (num2 > 0 && m_asyncHead !=
null)
527 TaskNode asyncHead = m_asyncHead;
528 RemoveAsyncWaiter(asyncHead);
529 QueueWaiterTask(asyncHead);
532 m_currentCount = currentCount;
533 if (m_waitHandle ==
null)
541 if (currentCount <= 0)
550 [SecuritySafeCritical]
551 private static void QueueWaiterTask(TaskNode waiterTask)
553 ThreadPool.UnsafeQueueCustomWorkItem(waiterTask, forceGlobal:
false);
557 [__DynamicallyInvokable]
567 [__DynamicallyInvokable]
568 protected virtual void Dispose(
bool disposing)
572 if (m_waitHandle !=
null)
574 m_waitHandle.
Close();
583 private static void CancellationTokenCanceledEventHandler(
object obj)
586 lock (semaphoreSlim.m_lockObj)
592 private void CheckDispose()
594 if (m_lockObj ==
null)
596 throw new ObjectDisposedException(
null, GetResourceString(
"SemaphoreSlim_Disposed"));
600 private static string GetResourceString(
string str)
602 return Environment.GetResourceString(str);
static Task< Task > WhenAny(params Task[] tasks)
Creates a task that will complete when any of the supplied tasks have completed.
Represents a lightweight alternative to T:System.Threading.Semaphore that limits the number of thread...
bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
Blocks the current thread until it can enter the T:System.Threading.SemaphoreSlim,...
Propagates notification that operations should be canceled.
new ConfiguredTaskAwaitable< TResult > ConfigureAwait(bool continueOnCapturedContext)
Configures an awaiter used to await this T:System.Threading.Tasks.Task`1.
Encapsulates operating system–specific objects that wait for exclusive access to shared resources.
void ThrowIfCancellationRequested()
Throws a T:System.OperationCanceledException if this token has had cancellation requested.
void Wait(CancellationToken cancellationToken)
Blocks the current thread until it can enter the T:System.Threading.SemaphoreSlim,...
static void PulseAll(object obj)
Notifies all waiting threads of a change in the object's state.
static void SuppressFinalize(object obj)
Requests that the common language runtime not call the finalizer for the specified object.
Task< bool > WaitAsync(TimeSpan timeout, CancellationToken cancellationToken)
Asynchronously waits to enter the T:System.Threading.SemaphoreSlim, using a T:System....
Provides support for spin-based waiting.
bool Set()
Sets the state of the event to signaled, allowing one or more waiting threads to proceed.
Task< bool > WaitAsync(TimeSpan timeout)
Asynchronously waits to enter the T:System.Threading.SemaphoreSlim, using a T:System....
Provides a mechanism for releasing unmanaged resources.To browse the .NET Framework source code for t...
int Release()
Releases the T:System.Threading.SemaphoreSlim object once.
The exception that is thrown when the value of an argument is outside the allowable range of values a...
Provides a mechanism that synchronizes access to objects.
Represents a callback delegate that has been registered with a T:System.Threading....
double TotalMilliseconds
Gets the value of the current T:System.TimeSpan structure expressed in whole and fractional milliseco...
bool CanBeCanceled
Gets whether this token is capable of being in the canceled state.
SemaphoreSlim(int initialCount)
Initializes a new instance of the T:System.Threading.SemaphoreSlim class, specifying the initial numb...
void Dispose()
Releases all resources used by the current instance of the T:System.Threading.SemaphoreSlim class.
static Task Delay(TimeSpan delay)
Creates a task that completes after a specified time interval.
bool IsCancellationRequested
Gets whether cancellation has been requested for this token.
int CurrentCount
Gets the number of remaining threads that can enter the T:System.Threading.SemaphoreSlim object.
bool NextSpinWillYield
Gets whether the next call to M:System.Threading.SpinWait.SpinOnce will yield the processor,...
Task WaitAsync(CancellationToken cancellationToken)
Asynchronously waits to enter the T:System.Threading.SemaphoreSlim, while observing a T:System....
TaskCreationOptions
Specifies flags that control optional behavior for the creation and execution of tasks.
bool Wait(TimeSpan timeout)
Blocks the current thread until it can enter the T:System.Threading.SemaphoreSlim,...
WaitHandle AvailableWaitHandle
Returns a T:System.Threading.WaitHandle that can be used to wait on the semaphore.
int Release(int releaseCount)
Releases the T:System.Threading.SemaphoreSlim object a specified number of times.
SecurityAction
Specifies the security actions that can be performed using declarative security.
static void Enter(object obj)
Acquires an exclusive lock on the specified object.
virtual void Dispose(bool disposing)
Releases the unmanaged resources used by the T:System.Threading.SemaphoreSlim, and optionally release...
Task WaitAsync()
Asynchronously waits to enter the T:System.Threading.SemaphoreSlim.
Task< bool > WaitAsync(int millisecondsTimeout, CancellationToken cancellationToken)
Asynchronously waits to enter the T:System.Threading.SemaphoreSlim, using a 32-bit signed integer to ...
Notifies one or more waiting threads that an event has occurred. This class cannot be inherited.
void Wait()
Blocks the current thread until it can enter the T:System.Threading.SemaphoreSlim.
static void Exit(object obj)
Releases an exclusive lock on the specified object.
SemaphoreSlim(int initialCount, int maxCount)
Initializes a new instance of the T:System.Threading.SemaphoreSlim class, specifying the initial and ...
bool Wait(TimeSpan timeout, CancellationToken cancellationToken)
Blocks the current thread until it can enter the T:System.Threading.SemaphoreSlim,...
The exception that is thrown when the Overload:System.Threading.Semaphore.Release method is called on...
virtual void Close()
Releases all resources held by the current T:System.Threading.WaitHandle.
Controls the system garbage collector, a service that automatically reclaims unused memory.
The exception that is thrown in a thread upon cancellation of an operation that the thread was execut...
void SpinOnce()
Performs a single spin.
static void Pulse(object obj)
Notifies a thread in the waiting queue of a change in the locked object's state.
Represents a time interval.To browse the .NET Framework source code for this type,...
new TaskAwaiter< TResult > GetAwaiter()
Gets an awaiter used to await this T:System.Threading.Tasks.Task`1.
The exception that is thrown when a call is made to the M:System.Threading.Thread....
Task< bool > WaitAsync(int millisecondsTimeout)
Asynchronously waits to enter the T:System.Threading.SemaphoreSlim, using a 32-bit signed integer to ...
bool Wait(int millisecondsTimeout)
Blocks the current thread until it can enter the T:System.Threading.SemaphoreSlim,...
void Dispose()
Releases all resources used by the current instance of the T:System.Threading.CancellationTokenRegist...
bool Reset()
Sets the state of the event to nonsignaled, causing threads to block.
Provides a pool of threads that can be used to execute tasks, post work items, process asynchronous I...
Represents an asynchronous operation that can return a value.