public bool PrioritizeAction(Action action) { ICancellationToken priorityToken = new GSF.Threading.CancellationToken(); ICancellationToken normalToken = null; bool cancelled = false; priorityToken.Cancel(); while (Interlocked.CompareExchange(ref m_cancellationToken, priorityToken, normalToken) != normalToken) { normalToken = Interlocked.CompareExchange(ref m_cancellationToken, null, null); cancelled = normalToken?.Cancel() ?? true; if (!cancelled) { return(false); } } TaskThread.Push(HighPriority, () => { try { action(); } finally { Interlocked.Exchange(ref m_cancellationToken, null); } }); return(true); }
/// <summary> /// Creates a new instance of the <see cref="LogicalThreadOperation"/> class. /// </summary> /// <param name="thread">The thread on which to execute the operation's action.</param> /// <param name="action">The action to be executed.</param> /// <param name="priority">The priority with which the action should be executed on the logical thread.</param> /// <param name="autoRunIfPending"> /// Set to <c>true</c> to execute <see cref="RunIfPending"/> automatically; otherwise, /// set to <c>false</c> for user controlled call timing. /// </param> /// <exception cref="ArgumentException"><paramref name="priority"/> is outside the range between 1 and <see cref="LogicalThread.PriorityLevels"/>.</exception> public LogicalThreadOperation(LogicalThread thread, Action action, int priority, bool autoRunIfPending = true) { m_thread = thread; m_action = action; Priority = priority; m_autoRunIfPending = autoRunIfPending; // Initialize this class with a cancelled token so that // calls to EnsurePriority before the first call to // ExecuteActionAsync do not inadvertently queue actions m_cancellationToken = new CancellationToken(); m_cancellationToken.Cancel(); }
/// <summary> /// Queues the given thread for execution. /// </summary> /// <param name="thread">The thread to be queued for execution.</param> private void Enqueue(LogicalThread thread) { ICancellationToken executionToken; int activePriority; int nextPriority; do { // Create the execution token to be used in the closure ICancellationToken nextExecutionToken = new CancellationToken(); // Always update the thread's active priority before // the execution token to mitigate race conditions nextPriority = thread.NextPriority; thread.ActivePriority = nextPriority; thread.NextExecutionToken = nextExecutionToken; // Now that the action can be cancelled by another thread using the // new cancellation token, it should be safe to put it in the queue m_logicalThreadQueues[PriorityLevels - nextPriority].Enqueue(() => { if (nextExecutionToken.Cancel()) { return(thread); } return(null); }); // Because enqueuing the thread is a multi-step process, we need to // double-check in case the thread's priority changed in the meantime activePriority = thread.ActivePriority; nextPriority = thread.NextPriority; // We can use the cancellation token we just created because we only // really need to double-check the work that was done on this thread; // in other words, if another thread changed the priority in the // meantime, it can double-check its own work executionToken = nextExecutionToken; }while (activePriority != nextPriority && executionToken.Cancel()); }
private void ExecuteActionAsync(int priority) { CancellationToken cancellationToken = new CancellationToken(); // Order of operations here is vital to avoid getting // cancelled when the user hasn't changed the priority level Interlocked.Exchange(ref m_queuedPriority, priority); Interlocked.Exchange(ref m_cancellationToken, cancellationToken); m_thread.Push(priority, () => { // If the cancellation token was previously cancelled, // it means this action has been requeued so don't do anything. // By cancelling it now, we let requeue operations know that the // action is currently executing and will soon be requeued anyway if (m_cancellationToken.Cancel()) { ExecuteAction(m_action); } }); }
public bool QueueAction(Action action) { ICancellationToken cancellationToken = new GSF.Threading.CancellationToken(); if (Interlocked.CompareExchange(ref m_cancellationToken, cancellationToken, null) != null) { return(false); } TaskThread.Push(NormalPriority, () => { if (!cancellationToken.Cancel()) { return; } try { action(); } finally { Interlocked.CompareExchange(ref m_cancellationToken, null, cancellationToken); } }); return(true); }
public void CancelEnumeration() { CancellationToken cancellationToken = Interlocked.CompareExchange(ref m_cancellationToken, null, null); cancellationToken?.Cancel(); }