public async Task <T> ReadAsync(CancellationToken cancellationToken, Func <T, bool> acceptanceTest) { while (!cancellationToken.IsCancellationRequested) { await readSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); T message; if (!writeQueue.TryDequeue(out message)) { throw new InvalidStateException(); } if (acceptanceTest(message)) { writeSemaphore?.Release(); return(message); } else { writeQueue.Enqueue(message); readSemaphore.Release(); } } // throw is guaranteed cancellationToken.ThrowIfCancellationRequested(); return(default(T)); }
public void TestWaitRelease() { var semaphore = new AsyncSemaphore(1); Assert.Equal(1, semaphore.Available); semaphore.Wait(); Assert.Equal(0, semaphore.Available); semaphore.Release(); Assert.Equal(1, semaphore.Available); }
public async Task WaitAsync_Release() { var semaphore = new AsyncSemaphore(1, 1, true); for (var i = 0; i < 1000; ++i) { await semaphore.WaitAsync(); semaphore.Release(); } }
public void Release() { var semaphore = new AsyncSemaphore(0, 5, true); var acquiredWhenNoneAvailable = semaphore.Wait(5, 0); semaphore.Release(5); var acquiredWhenAllAvailable = semaphore.Wait(5, 0); Assert.False(acquiredWhenNoneAvailable); Assert.True(acquiredWhenAllAvailable); }
public void Release_WithoutWaiters_IncrementsCount() { AsyncSemaphore semaphore = new AsyncSemaphore(0); Assert.Equal(0, semaphore.CurrentCount); semaphore.Release(); Assert.Equal(1, semaphore.CurrentCount); Task task = semaphore.WaitAsync(); Assert.Equal(0, semaphore.CurrentCount); Assert.True(task.IsCompleted); }
public async Task Release_WithWaiters_ReleasesWaiters() { AsyncSemaphore semaphore = new AsyncSemaphore(0); Assert.Equal(0, semaphore.CurrentCount); Task task = semaphore.WaitAsync(); Assert.Equal(0, semaphore.CurrentCount); Assert.False(task.IsCompleted); semaphore.Release(); Assert.Equal(0, semaphore.CurrentCount); await task; }
public void WhenClientRelease_SemaphoreShouldNotMakeOneMoreClientWaitedAsync() { var sut = new AsyncSemaphore(1); sut.Wait(); var task = sut.WaitAsync(); ConcurrentAssert.EnsureThatTaskIsNeverCompleted(task); sut.Release(); ConcurrentAssert.EnsureThatTaskIsCompleted(task); }
/// <summary> /// Downloads remoteUri to dest. This method is solely used for downloading /// covers from discogs, which requires OAuth Authentication. Therefore, note /// the use of oAuthHttpClient. /// </summary> /// <param name="remoteUri">remote URI to download</param> /// <returns>a local URI to the downloaded file</returns> public async Task <Uri> Download(Uri remoteUri, string dest) { // might throw at least IsolatedStorageException on WP await sem.WaitAsync(); try { await fileUtils.WithFileWriteAsync(dest, stream => { return(httpClient.DownloadToStream(remoteUri, stream)); }); } finally { sem.Release(); } return(await UriFromPath(dest)); }
public void Release_WithWaiters_ReleasesWaiters() { AsyncContext.Run(async() => { var semaphore = new AsyncSemaphore(0); Assert.AreEqual(0, semaphore.CurrentCount); var task = semaphore.WaitAsync(); Assert.AreEqual(0, semaphore.CurrentCount); Assert.IsFalse(task.IsCompleted); semaphore.Release(); Assert.AreEqual(0, semaphore.CurrentCount); await task; }); }
public bool AddOrReplace(WorkItem item) { lock (_gate) { if (AddOrReplace_NoLock(item)) { // increase count _semaphore.Release(); return(true); } return(false); } }
/// <summary> /// Executes the request but limits the number of threads that can be used /// </summary> /// <typeparam name="T"></typeparam> /// <param name="request"></param> /// <returns></returns> public async Task <IApiResponse <T> > EnqueueAsync <T>(IApiRequest request) where T : class { await _throttler.WaitAsync().ConfigureAwait(false); try { return(await _handler.ExecuteAsync <T>(request).ConfigureAwait(false)); } finally { _throttler.Release(); } }
/// <summary> /// Executes the request but limits the number of threads that can be used /// </summary> /// <typeparam name="T"></typeparam> /// <param name="request"></param> /// <returns></returns> public async Task <IBoxResponse <T> > EnqueueAsync <T>(IBoxRequest request) where T : class { await _throttler.WaitAsync(); try { return(await _handler.ExecuteAsync <T>(request)); } finally { _throttler.Release(); } }
protected async override Task WriteMessageInternal(string message) { await lcdLock.WaitAsync(); try { Debug.WriteLine("HD44780GpioDriver: Writing Message - " + message); await this.writeValue(Register.Instruction, InstructionCode_ClearLcd); await this.wait(TimeSpan.FromMilliseconds(1.64)); int totalChars = 0; int lineChars = 0; int lines = 1; foreach (char c in message) { if (this.Width == lineChars) { Debug.WriteLine("HD44780GpioDriver: Message overran on line" + lines); } if (this.Height < lines) { Debug.WriteLine("HD44780GpioDriver: Message contains too many lines"); } if (c == '\n') { await this.writeValue(Register.Instruction, InstructionCode_NewLine); lines++; lineChars = 0; continue; } await this.writeValue(Register.Data, (short)c); totalChars++; lineChars++; await this.wait(TimeSpan.FromMilliseconds(1)); } Debug.WriteLine("HD44780GpioDriver: Message write complete"); } finally { lcdLock.Release(); } }
public IExchange DeclareExchange(IAdvancedBus advancedBus, string exchangeName, string exchangeType) { IExchange exchange; if (exchanges.TryGetValue(exchangeName, out exchange)) { return(exchange); } semaphore.Wait(); try { if (exchanges.TryGetValue(exchangeName, out exchange)) { return(exchange); } exchange = advancedBus.ExchangeDeclare(exchangeName, exchangeType); exchanges[exchangeName] = exchange; return(exchange); } finally { semaphore.Release(); } }
public async Task WaitAsync_Random() { var semaphore = new AsyncSemaphore(1000, 1000, true); var random = new Random(1234); var amountLeft = 1000; while (amountLeft > 0) { var maxToAcquire = amountLeft / 2; var amountToAcquire = random.Next(1, maxToAcquire > 1 ? maxToAcquire : 1); Assert.True(await semaphore.WaitAsync(amountToAcquire, 0)); amountLeft -= amountToAcquire; } semaphore.Release(1000); Assert.True(await semaphore.WaitAsync(1000, 0)); }
public override void Return(T item) { lock (SyncObject) { if (m_Stack == null) { if (item is IDisposable disposable) { disposable.Dispose(); } return; } m_Stack.Push(item); m_Semaphore.Release(); } }
public async Task MultipleAsynchronousAcquire_Fair() { var semaphore = new AsyncSemaphore(0, 1, true); var completionTasks = Enumerable.Range(0, 10).Select(_ => { return(new TaskCompletionSource <bool>()); }).ToList(); var acquireTasks = new List <Task>(); for (var i = 0; i < 10; ++i) { var index = i; var acquireTask = Task.Run(async() => { await semaphore.WaitAsync(); completionTasks[index].SetResult(true); }); await Task.Delay(100); while (acquireTask.Status != TaskStatus.Running) { await Task.Delay(100); } } Assert.True(completionTasks.All(t => t.Task.Status != TaskStatus.RanToCompletion)); for (var i = 0; i < 10; ++i) { for (var finished = 0; finished < i; ++finished) { Assert.True(completionTasks[finished].Task.IsCompletedSuccessfully); } for (var running = i; running < 10; ++running) { Assert.NotEqual(TaskStatus.RanToCompletion, completionTasks[running].Task.Status); } semaphore.Release(); await Task.Delay(100); } Assert.True(completionTasks.All(t => t.Task.IsCompletedSuccessfully)); }
public async Task WaitAsync_Cancelled_DoesNotTakeSlot() { AsyncSemaphore semaphore = new AsyncSemaphore(0); Assert.Equal(0, semaphore.CurrentCount); CancellationTokenSource cts = new CancellationTokenSource(); Task task = semaphore.WaitAsync(cts.Token); Assert.Equal(0, semaphore.CurrentCount); Assert.False(task.IsCompleted); cts.Cancel(); try { await task; } catch (OperationCanceledException) { } semaphore.Release(); Assert.Equal(1, semaphore.CurrentCount); Assert.True(task.IsCanceled); }
public void WaitAsync_Cancelled_DoesNotTakeSlot() { Test.Async(async() => { var semaphore = new AsyncSemaphore(0); Assert.AreEqual(0, semaphore.CurrentCount); var cts = new CancellationTokenSource(); var task = semaphore.WaitAsync(cts.Token); Assert.AreEqual(0, semaphore.CurrentCount); Assert.IsFalse(task.IsCompleted); cts.Cancel(); try { await task; } catch (OperationCanceledException) { } semaphore.Release(); Assert.AreEqual(1, semaphore.CurrentCount); Assert.IsTrue(task.IsCanceled); }); }
public bool AddOrReplace(WorkItem item) { if (!HasAnyWork) { // first work is added. _progressReporter.Start(); } lock (_gate) { if (AddOrReplace_NoLock(item)) { // increase count _semaphore.Release(); return(true); } return(false); } }
/// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// </summary> public void Dispose() { AsyncSemaphore[] semaphores = Interlocked.Exchange(ref _semaphores, null); if (semaphores == null) { return; } List <Exception> ex = null; for (int i = 0; i < semaphores.Length; i++) { try { AsyncSemaphore sem = Interlocked.Exchange(ref semaphores[i], null); sem?.Release(); } catch (Exception e) { if (ex == null) { ex = new List <Exception>(); } ex.Add(e); } } if (ex == null || ex.Count < 1) { return; } // ReSharper disable once AssignNullToNotNullAttribute if (ex.Count < 2) { ex[0].ReThrow(); } throw new AggregateException(ex); }
public async Task <SteamCdnClient> GetClientAsync(CancellationToken cancellationToken = default) { await _getClientSemaphore.WaitAsync(cancellationToken); if (_cdnClients.Count == 0) { await FillPoolAsync(); } // Select client that has been handed out the least yet var cdnClient = _cdnClients .OrderBy(x => x.Key.Errors) .ThenBy(x => x.Value) .First() .Key; _cdnClients[cdnClient]++; _getClientSemaphore.Release(); return(cdnClient); }
/// <summary> /// Asynchronously downloads meta-information for one file. /// </summary> /// <param name="service">Google Drive service that is used to download files metainformation.</param> /// <param name="file">File with filled Id field.</param> /// <param name="semaphore">Semaphore used to throttle downloading process.</param> /// <returns>Asynchronous task that downloads meta-information.</returns> private async Task <File> DownloadFileMetaInformation(DriveService service, File file, AsyncSemaphore semaphore) { var fileInfoRequest = service.Files.Get(file.Id); fileInfoRequest.Fields = "*"; await semaphore.WaitAsync(); try { var fileInfo = await GoogleRequestHelper.Execute( fileInfoRequest.ExecuteAsync, this.CancellationToken, GoogleRequestHelper.Cooldown *Utils.Constants.DownloadThreadsCount); ++this.Progress; this.StatusAccumulator.SuccessItem(); return(fileInfo); } catch (Exception e) { if (this.CancellationToken.IsCancellationRequested) { throw; } this.Log.LogError($"Downloading meta-information for file {file.Name} failed.", e); this.StatusAccumulator.FailureOccurred(); throw; } finally { semaphore.Release(); } }
private async Task SendHelperAsync(Guid destination, MessageDto message) { Debug( $"Sending to {destination.ToString("n").Substring(0, 6)} message {message}. " + Environment.NewLine + $"clientIdentity matches destination: {remoteIdentity.Matches(destination, IdentityMatchingScope.Broadcast)}"); if (!isHandshakeComplete || !remoteIdentity.Matches(destination, IdentityMatchingScope.Broadcast)) { return; } var completionLatch = new AsyncLatch(); sendCompletionLatchByMessage.AddOrThrow(message, completionLatch); outboundMessageQueue.Enqueue(message); outboundMessageSignal.Release(); Debug($"Awaiting completion for send to {destination.ToString("n").Substring(0, 6)} message {message}."); await completionLatch.WaitAsync().ConfigureAwait(false); sendCompletionLatchByMessage.RemoveOrThrow(message, completionLatch); Debug($"Completed send to {destination.ToString("n").Substring(0, 6)} message {message}."); }
/// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// </summary> public void Dispose() { _semaphore?.Release(); }
async Task SendBatch() { batchId++; if (batchId >= long.MaxValue) { batchId = 1; } // Pause the timer timerBatchWait.Change(Timeout.Infinite, Timeout.Infinite); if (notifications.Count <= 0) { return; } // Let's store the batch items to send internally var toSend = new List <CompletableApnsNotification> (); while (notifications.Count > 0 && toSend.Count < Configuration.InternalBatchSize) { var n = notifications.Dequeue(); toSend.Add(n); } Log.Info("APNS-Client[{0}]: Sending Batch ID={1}, Count={2}", id, batchId, toSend.Count); try { var data = createBatch(toSend); if (data != null && data.Length > 0) { for (var i = 0; i <= Configuration.InternalBatchFailureRetryCount; i++) { await connectingSemaphore.WaitAsync(); try { // See if we need to connect if (!socketCanWrite() || i > 0) { await connect(); } } finally { connectingSemaphore.Release(); } try { await networkStream.WriteAsync(data, 0, data.Length).ConfigureAwait(false); break; } catch (Exception ex) when(i != Configuration.InternalBatchFailureRetryCount) { Log.Info("APNS-CLIENT[{0}]: Retrying Batch: Batch ID={1}, Error={2}", id, batchId, ex); } } foreach (var n in toSend) { sent.Add(new SentNotification(n)); } } } catch (Exception ex) { Log.Error("APNS-CLIENT[{0}]: Send Batch Error: Batch ID={1}, Error={2}", id, batchId, ex); foreach (var n in toSend) { n.CompleteFailed(new ApnsNotificationException(ApnsNotificationErrorStatusCode.ConnectionError, n.Notification, ex)); } } Log.Info("APNS-Client[{0}]: Sent Batch, waiting for possible response...", id); try { await Reader(); } catch (Exception ex) { Log.Error("APNS-Client[{0}]: Reader Exception: {1}", id, ex); } Log.Info("APNS-Client[{0}]: Done Reading for Batch ID={1}, reseting batch timer...", id, batchId); // Restart the timer for the next batch timerBatchWait.Change(Configuration.InternalBatchingWaitPeriod, new TimeSpan(0, 0, 0, 0, -1)); }
/// <summary> /// Downloads binary (non-"Google Docs") file. /// </summary> /// <param name="service">Google Drive service used to download a file.</param> /// <param name="file">Meta-information about file to download.</param> /// <param name="semaphore">Semaphore used to throttle downloading process.</param> /// <param name="unitsOfWork">Abstract units of work assigned to download this file. Used in progress reporting.</param> /// <param name="directories">Dictionary that contains possible directories to save a file.</param> /// <returns>Information about downloaded file, null if downloading failed.</returns> /// <exception cref="InternalErrorException">Something is wrong with downloader code itself.</exception> public async Task <DownloadedFile> DownloadBinaryFile( DriveService service, File file, AsyncSemaphore semaphore, int unitsOfWork, IDictionary <File, IEnumerable <DirectoryInfo> > directories) { this.Info = file.Name; this.Estimation = unitsOfWork; if (file.Size.HasValue && (file.Size.Value == 0)) { try { var fileName = FileDownloadUtils.GetFileName(file, directories); System.IO.File.Create(fileName); this.Done(); return(new DownloadedFile(file, fileName)); } catch (Exception e) { this.Log.LogError($"Saving zero-length file '{file.Name}' error.", e); this.StatusAccumulator.FailureOccurred(); throw; } } var request = service.Files.Get(file.Id); request.MediaDownloader.ProgressChanged += downloadProgress => { switch (downloadProgress.Status) { case DownloadStatus.NotStarted: break; case DownloadStatus.Downloading: this.Progress = (int)(downloadProgress.BytesDownloaded * unitsOfWork / (file.Size ?? 1)); break; case DownloadStatus.Completed: this.Progress = this.Estimation; break; case DownloadStatus.Failed: this.Progress = this.Estimation; if (!this.CancellationToken.IsCancellationRequested) { this.Status = Status.Error; this.Log.LogError($"Downloading file '{file.Name}' error.", downloadProgress.Exception); this.StatusAccumulator.FailureOccurred(); } break; default: throw new InternalErrorException("DownloadStatus enum contains unknown value."); } }; await semaphore.WaitAsync(); this.Log.LogDebugMessage($"Starting to download '{file.Name}' binary file."); try { var fileName = FileDownloadUtils.GetFileName(file, directories); using (var fileStream = new FileStream(fileName, FileMode.Create)) { await GoogleRequestHelper.Execute( ct => request.DownloadAsync(fileStream, ct), this.CancellationToken, GoogleRequestHelper.Cooldown *Utils.Constants.DownloadThreadsCount); } var fileInfo = FileDownloadUtils.CorrectFileTimes(file, fileName); this.Log.LogDebugMessage($"File '{file.Name}' downloading finished, saved as {fileInfo.FullName}."); this.StatusAccumulator.SuccessItem(); this.Done(); return(new DownloadedFile(file, fileInfo.FullName)); } catch (Exception e) { if (this.CancellationToken.IsCancellationRequested) { throw; } this.Log.LogError($"Downloading file '{file.Name}' error.", e); this.StatusAccumulator.FailureOccurred(); throw; } finally { semaphore.Release(); } }
/// <summary> /// A probe attempt to one destination. /// </summary> private async Task ProbeDestinationAsync(DestinationInfo destination, AsyncSemaphore semaphore, CancellationToken cancellationToken) { // Conduct a dither for every endpoint probe to optimize concurrency. var randomDither = _randomFactory.CreateRandomInstance(); await _timer.Delay(TimeSpan.FromMilliseconds(randomDither.Next(_ditheringIntervalInMilliseconds)), cancellationToken); var outcome = HealthProbeOutcome.Unknown; string logDetail = null; // Enforce max concurrency. await semaphore.WaitAsync(); Log.ProberStarted(_logger, BackendId, destination.DestinationId); try { using (var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(_cts.Token)) { // Set up timeout and start probing. timeoutCts.CancelAfter(_httpTimeoutInterval, _timer); var response = await _operationLogger.ExecuteAsync( "ReverseProxy.Service.HealthProbe", () => _backendProbeHttpClient.GetAsync(new Uri(new Uri(destination.Config.Value.Address, UriKind.Absolute), _healthControllerUrl), timeoutCts.Token)); // Collect response status. outcome = response.IsSuccessStatusCode ? HealthProbeOutcome.Success : HealthProbeOutcome.HttpFailure; logDetail = $"Received status code {(int)response.StatusCode}"; } } catch (HttpRequestException ex) { // If there is a error during the http request process. Swallow the error and log error message. outcome = HealthProbeOutcome.TransportFailure; logDetail = ex.Message; } catch (OperationCanceledException) { // If the cancel requested by our StopAsync method. It is a expected graceful shut down. if (_cts.IsCancellationRequested) { outcome = HealthProbeOutcome.Canceled; logDetail = "Operation deliberately canceled"; throw; } else { outcome = HealthProbeOutcome.Timeout; logDetail = $"Health probe timed out after {Config.HealthCheckOptions.Interval.TotalSeconds} second"; } } catch (Exception ex) { throw new Exception($"Prober for '{destination.DestinationId}' encounters unexpected exception.", ex); } finally { if (outcome != HealthProbeOutcome.Canceled) { // Update the health state base on the response. var healthState = outcome == HealthProbeOutcome.Success ? DestinationHealth.Healthy : DestinationHealth.Unhealthy; destination.DynamicState.Value = new DestinationDynamicState(healthState); Log.ProberResult(_logger, destination.DestinationId, outcome, logDetail); } // The probe operation is done, release the semaphore to allow other probes to proceed. semaphore.Release(); } }
public async Task Update() { // TODO: Ensure only one Update is running across all instances of SMA (in case SMA is closed during the update process) // TODO: Offer manual updates // TODO: Add option to wait for user confirmation to update if (UpdateEnabled == false) { return; } try { if (Wininet.HasNetworking() == false) { return; } CancellationTokenSource cts = new CancellationTokenSource(0); cts.Cancel(); using (await _semaphore.LockAsync(cts.Token)) using (var updateMgr = CreateUpdateMgr()) { State = SMAUpdateState.Fetching; var updateInfo = await updateMgr.CheckForUpdate(false, progress => ProgressPct = progress); if (updateInfo?.ReleasesToApply == null) { State = SMAUpdateState.Error; return; } if (updateInfo.ReleasesToApply.None()) { State = SMAUpdateState.UpToDate; return; } State = SMAUpdateState.Downloading; await updateMgr.DownloadReleases(updateInfo.ReleasesToApply, progress => ProgressPct = progress); State = SMAUpdateState.Applying; await updateMgr.ApplyReleases(updateInfo, progress => ProgressPct = progress); State = SMAUpdateState.CreatingUninstaller; await updateMgr.CreateUninstallerRegistryEntry(); State = SMAUpdateState.Updated; } } catch (TaskCanceledException) {} catch (Exception ex) // TODO: Update Squirrel UpdateManager to send sub-classed Exceptions { LogTo.Warning(ex, $"An exception was caught while {State.Name().ToLower()} update"); State = SMAUpdateState.Error; } finally { _semaphore.Release(); } }