/// <summary> /// Starts the thread. /// </summary> public void Start() { if (_currentState != BackgroundLoopState.None) { throw new InvalidOperationException("Unable to start thread: Illegal state: " + _currentState + "!"); } //Ensure that one single pass of the main loop is made at once _mainLoopSynchronizeObject.Release(); // Create stop semaphore if (_threadStopSynchronizeObject != null) { _threadStopSynchronizeObject.Dispose(); _threadStopSynchronizeObject = null; } _threadStopSynchronizeObject = new SemaphoreSlim(0); //Go into starting state _currentState = BackgroundLoopState.Starting; _mainThread = new Thread(this.BackgroundLoopMainMethod) { IsBackground = true, Name = this.Name }; _mainThread.Start(); }
/// <summary> /// Stops this instance. /// </summary> public void Stop() { if (_currentState != BackgroundLoopState.Running) { throw new InvalidOperationException($"Unable to stop thread: Illegal state: {_currentState}!"); } _currentState = BackgroundLoopState.Stopping; while (_taskQueue.TryDequeue(out _)) { } //Trigger next update this.Trigger(); }
/// <summary> /// The thread's main method. /// </summary> private void BackgroundLoopMainMethod() { if (_mainThread == null) { return; } if (_mainThread != Thread.CurrentThread) { return; } try { _mainThread.CurrentCulture = _culture; _mainThread.CurrentUICulture = _uiCulture; var stopWatch = new Stopwatch(); stopWatch.Start(); //Set synchronization context for this thread SynchronizationContext.SetSynchronizationContext(_syncContext); //Notify start process try { CurrentBackgroundLoop = this; this.OnStarting(EventArgs.Empty); } catch (Exception ex) { this.OnThreadException(new BackgroundLoopExceptionEventArgs(_currentState, ex)); _currentState = BackgroundLoopState.None; CurrentBackgroundLoop = null; return; } //Run main-thread if (_currentState != BackgroundLoopState.None) { _currentState = BackgroundLoopState.Running; while (_currentState == BackgroundLoopState.Running) { try { //Wait for next action to perform _mainLoopSynchronizeObject.Wait(this.HeartBeat); //Measure current time stopWatch.Stop(); var elapsedTicks = stopWatch.Elapsed.Ticks; stopWatch.Reset(); stopWatch.Start(); // Get current task queue var localTaskQueue = new List <Action>(); while (_taskQueue.TryDequeue(out var dummyAction)) { localTaskQueue.Add(dummyAction); } // Execute all tasks foreach (var actTask in localTaskQueue) { try { actTask(); } catch (Exception ex) { this.OnThreadException(new BackgroundLoopExceptionEventArgs(_currentState, ex)); } } // Performs a tick this.OnTick(new BackgroundLoopTickEventArgs(elapsedTicks)); } catch (Exception ex) { this.OnThreadException(new BackgroundLoopExceptionEventArgs(_currentState, ex)); } } // Notify stop process try { this.OnStopping(EventArgs.Empty); } catch (Exception ex) { this.OnThreadException(new BackgroundLoopExceptionEventArgs(_currentState, ex)); } CurrentBackgroundLoop = null; } // Reset state to none _currentState = BackgroundLoopState.None; stopWatch.Stop(); stopWatch = null; } catch (Exception ex) { this.OnThreadException(new BackgroundLoopExceptionEventArgs(_currentState, ex)); _currentState = BackgroundLoopState.None; } // Notify thread stop event try { _threadStopSynchronizeObject?.Release(); } catch (Exception) { // ignored } }
/// <summary> /// Initializes a new instance of the <see cref="BackgroundLoopExceptionEventArgs"/> class. /// </summary> /// <param name="threadState">The current state of the <see cref="BackgroundLoop"/>.</param> /// <param name="innerException">The inner exception.</param> public BackgroundLoopExceptionEventArgs(BackgroundLoopState threadState, Exception innerException) { this.Exception = innerException; this.State = threadState; }