/// <summary> /// Called when an enqueue event is received. This toggles the WaitEvent allowing further entries to be processed. /// </summary> private void Queue_EnqueuedReceived(object sender, EventArgs e) { if (!(State == ActionerState.Stopped || State == ActionerState.Stopping)) { WaitForQueueEvent.Set( ); } }
/// <summary> /// Stop the Actioner /// </summary> /// <param name="timeoutMs">How long to wait in ms for the actioner to complete, -1 to wait forever</param> /// <returns>true if thread was or is stopped.</returns> public bool Stop(int timeoutMs = -1) { if (State != ActionerState.Stopped) { lock (_syncRoot) { if (State == ActionerState.Running || State == ActionerState.WaitingForQueue || State == ActionerState.WaitingForTask) { State = ActionerState.Stopping; } } // cancel running tasks CancelTokenSrc?.Cancel(); } // Get rid of the looping thread if (LoopingThread != null) { WaitForQueueEvent.Set(); WaitForTaskEvent.Set(); if (LoopingThread.Join(timeoutMs)) { LoopingThread = null; return(true); } return(false); } return(true); }
/// <summary> /// The loop that pulls elements from the Queue and acts upon them. /// </summary> private void ActionLoop() { var lastReport = DateTime.UtcNow; while (true) { if (DateTime.UtcNow - lastReport > TimeSpan.FromMilliseconds(TaskReportingTime)) { lastReport = DateTime.UtcNow; Report(); } try { switch (State) { case ActionerState.Running: if (_semaphore.WaitOne(0)) { T next = Queue.Dequeue(); if (next != null) { QueueAction(next); } else { SetStateIfNotStopping(ActionerState.WaitingForQueue); } _semaphore.Release( ); } else { SetStateIfNotStopping(ActionerState.WaitingForTask); } break; case ActionerState.WaitingForQueue: WaitForQueueEvent.WaitOne(TaskReportingTime); SetStateIfNotStopping(ActionerState.Running); break; case ActionerState.WaitingForTask: WaitForTaskEvent.WaitOne(TaskReportingTime); SetStateIfNotStopping(ActionerState.Running); break; case ActionerState.Stopping: if (!Task.WaitAll(RunningTasks.Keys.ToArray(), TaskStopWait)) { EventLog.Application.WriteError("Failed to stop all the running tasks when shutting down QueueActioner."); } State = ActionerState.Stopped; Report(); return; case ActionerState.Stopped: EventLog.Application.WriteError("A Stopped thread should not be processing."); return; } } catch (Exception ex) { EventLog.Application.WriteError($"Unhandled exception in QueueAction loop. Exception: {ex}"); // exception not rethrown } } }