public async Task StartAsync() { // ReSharper disable once MethodSupportsCancellation await runningInstanceSemaphore.WaitAsync(); try { if (runningInstance != null) { return; } runningInstance = new AsyncTimerStartedInstance(cancellationToken); #pragma warning disable 4014 // Don't await, just schedule in background // ReSharper disable once MethodSupportsCancellation Task.Run(() => MainLoopAsync(runningInstance)); #pragma warning restore 4014 } finally { runningInstanceSemaphore.Release(); } }
private async Task MainLoopAsync([NotNull] AsyncTimerStartedInstance currentInstance) { if (currentInstance == null) { throw new ArgumentNullException(nameof(currentInstance)); } try { currentInstance.CancellationToken.ThrowIfCancellationRequested(); await Task.Delay(initialDelay, currentInstance.CancellationToken); do { currentInstance.CancellationToken.ThrowIfCancellationRequested(); var actions = Elapsed ?.GetInvocationList() .ToArray() .Cast <AsyncTimerActionDelegate>(); if (actions == null) { continue; } var cancellationTokenCopy = currentInstance.CancellationToken; await Task.WhenAll(actions.Select(async action => { try { await action(cancellationTokenCopy); } catch (Exception exception) { try { var task = ExceptionOccurred?.Invoke(action, exception); if (task != null) { await task; } } catch { /* ignored */ } } })); currentInstance.CancellationToken.ThrowIfCancellationRequested(); await Task.Delay(interval, currentInstance.CancellationToken); }while (autoReset); } catch (TaskCanceledException) { /* expected */ } finally { // ReSharper disable once MethodSupportsCancellation await runningInstanceSemaphore.WaitAsync(); try { if (runningInstance == currentInstance) { runningInstance = null; } } finally { runningInstanceSemaphore.Release(); } try { currentInstance.Dispose(); } catch { /* ignored */ } } }