/// <summary> /// Shuts down all the channel creators. /// </summary> /// <returns></returns> public Task ShutdownAsync() { _readWriteLock.EnterWriteLock(); try { if (_shutdown) { _tcsReservationDone.SetException(new TaskFailedException("Already shutting down.")); return _tcsReservationDone.Task; } _shutdown = true; } finally { _readWriteLock.ExitWriteLock(); } // Fast shutdown for those that are in the queue is not required. // Let the executor finish since the shutdown-flag is set and the // future will be set as well to "shutting down". // .NET-specific: queued tasks cannot be aborted, but the flag indicates // the shutdown and the result will be set to failed // the channel creator doesn't change anymore from here on int size = _channelCreators.Count; if (size == 0) { _tcsReservationDone.SetResult(null); } else { var completeCounter = new VolatileInteger(0); foreach (var channelCreator in _channelCreators) { // It's important to set the listener before calling shutdown. channelCreator.ShutdownTask.ContinueWith(delegate { if (completeCounter.IncrementAndGet() == size) { // we can block here _semaphoreUdp.Acquire(_maxPermitsUdp); _semaphoreTcp.Acquire(_maxPermitsTcp); _semaphorePermanentTcp.Acquire(_maxPermitsPermanentTcp); _tcsReservationDone.SetResult(null); } }); channelCreator.ShutdownAsync(); } } return _tcsReservationDone.Task; }
public Task ShutdownAsync() { if (_timer != null) { // .NET-specific ExecutorService.Cancel(_timer); } var tcsShutdown = new TaskCompletionSource<object>(); lock (_lock) { _shutdown = true; int max = _runningTasks.Count; if (max == 0) { tcsShutdown.SetResult(null); return tcsShutdown.Task; } var counter = new VolatileInteger(0); foreach (var task in _runningTasks.Keys) { task.ContinueWith(t => { if (counter.IncrementAndGet() == max) { tcsShutdown.SetResult(null); // complete } }); } } return tcsShutdown.Task; }