/// <summary> /// Creates a new time model, optionally providing a starting time and increment /// </summary> /// <param name="increment">The amount of time to increment on each iteration, defaults to one 100 nanosecond tick</param> /// <param name="now">The starting time, defaults to zero</param> public Time(TimeSpan?increment = null, TimeSpan?now = null) : base() { this.Name = "TimeThread"; Increment = increment.HasValue ? increment.Value : TimeSpan.FromTicks(1); Now = now.HasValue ? now.Value : TimeSpan.Zero; InvokeNextCycle(() => current = this); EndOfCycle.SubscribeForLifetime(() => Now = Now.Add(Increment), this); this.OnDisposed(() => { foreach (var func in Functions) { func.Lifetime.TryDispose(); } }); }
private void Loop() { try { stopRequested = false; Cycle = -1; LoopStarted.Fire(); List <SynchronizedEvent> todoOnThisCycle = new List <SynchronizedEvent>(); while (stopRequested == false) { if (Cycle == long.MaxValue) { Cycle = 0; } else { Cycle++; } try { StartOfCycle.Fire(); } catch (Exception ex) { var handling = HandleWorkItemException(ex, null); if (handling == EventLoopExceptionHandling.Throw) { throw; } else if (handling == EventLoopExceptionHandling.Stop) { return; } else if (handling == EventLoopExceptionHandling.Swallow) { // swallow } } lock (workQueue) { while (workQueue.Count > 0) { var workItem = workQueue[0]; workQueue.RemoveAt(0); todoOnThisCycle.Add(workItem); } } for (var i = 0; i < pendingWorkItems.Count; i++) { if (pendingWorkItems[i].IsFinished && pendingWorkItems[i].IsFailed) { var handling = HandleWorkItemException(pendingWorkItems[i].Exception, pendingWorkItems[i]); if (handling == EventLoopExceptionHandling.Throw) { ExceptionDispatchInfo.Capture(pendingWorkItems[i].Exception).Throw(); } else if (handling == EventLoopExceptionHandling.Stop) { return; } else if (handling == EventLoopExceptionHandling.Swallow) { // swallow } var wi = pendingWorkItems[i]; pendingWorkItems.RemoveAt(i--); pool.Return(wi); if (stopRequested) { return; } } else if (pendingWorkItems[i].IsFinished) { var wi = pendingWorkItems[i]; pendingWorkItems.RemoveAt(i--); pool.Return(wi); if (stopRequested) { return; } } } foreach (var workItem in todoOnThisCycle) { try { workItem.Run(); if (workItem.IsFinished == false) { pendingWorkItems.Add(workItem); } else if (workItem.Exception != null) { throw new AggregateException(workItem.Exception); } else { pool.Return(workItem); if (stopRequested) { return; } } } catch (Exception ex) { var handling = HandleWorkItemException(ex, workItem); if (handling == EventLoopExceptionHandling.Throw) { throw; } else if (handling == EventLoopExceptionHandling.Stop) { return; } else if (handling == EventLoopExceptionHandling.Swallow) { // swallow } } } todoOnThisCycle.Clear(); try { EndOfCycle.Fire(); } catch (Exception ex) { var handling = HandleWorkItemException(ex, null); if (handling == EventLoopExceptionHandling.Throw) { throw; } else if (handling == EventLoopExceptionHandling.Stop) { return; } else if (handling == EventLoopExceptionHandling.Swallow) { // swallow } } } } finally { IsDrainingOrDrained = true; LoopStopped.Fire(); SynchronizationContext.SetSynchronizationContext(null); } }