/// <summary> /// Invoke a zero arg action. /// </summary> /// <param name="handler">Action to invoke.</param> public void Invoke(Action handler) { if (handler == null) { throw new ArgumentNullException("handler"); } if (_referenceCount < 1) { throw new InvalidOperationException("Cannot call invoke an unaquired TaskEnv"); } #pragma warning disable 219 System.Diagnostics.StackTrace stacktrace = DebugUtil.GetStackTrace(); #pragma warning restore 219 // check if handler can be invoked in-place or needs to queued up if (_dispatchQueue != null) { _dispatchQueue.QueueWorkItem(() => { // store current thread-specific settings TaskEnv previousEnv = _currentEnv; try { // set thread-specific settings _currentEnv = this; // execute handler handler(); } catch (Exception e) { _log.ErrorExceptionMethodCall(e, "Invoke: unhandled exception in handler"); } finally { Release(); // restore thread-specific settings _currentEnv = previousEnv; } }); } else { // store current thread-specific settings TaskEnv previousEnv = _currentEnv; try { // set thread-specific settings _currentEnv = this; // execute handler handler(); } catch (Exception e) { _log.WarnExceptionMethodCall(e, "Invoke: unhandled exception in handler"); } finally { Release(); // restore thread-specific settings _currentEnv = previousEnv; } } }
/// <summary> /// Enqueue a callback as a work item to be invoked with a provided <see cref="TaskEnv"/>. /// </summary> /// <typeparam name="T">Result value type of callback.</typeparam> /// <param name="dispatchQueue">DispatchQueue to enqueue work into.</param> /// <param name="callback">Work item callback.</param> /// <param name="env">Environment for work item invocation.</param> /// <param name="result">Synchronization handle for work item.</param> /// <returns>The synchronization handle provided to the method.</returns> public static Result <T> QueueWorkItemWithEnv <T>(this IDispatchQueue dispatchQueue, Func <T> callback, TaskEnv env, Result <T> result) { if (env == null) { throw new ArgumentException("env"); } dispatchQueue.QueueWorkItem(env.MakeAction(callback, result)); return(result); }
/// <summary> /// Enqueue a callback as a work item to be invoked with the current <see cref="TaskEnv"/>. /// </summary> /// <typeparam name="T">Result value type of callback.</typeparam> /// <param name="dispatchQueue">DispatchQueue to enqueue work into.</param> /// <param name="callback">Work item callback.</param> /// <param name="result">Synchronization handle for work item.</param> /// <returns>The synchronization handle provided to the method.</returns> public static Result <T> QueueWorkItemWithCurrentEnv <T>(this IDispatchQueue dispatchQueue, Func <T> callback, Result <T> result) { var current = TaskEnv.CurrentOrNull; if (current != null) { return(dispatchQueue.QueueWorkItemWithEnv(callback, current, result)); } if (result != null) { dispatchQueue.QueueWorkItem(delegate() { try { result.Return(callback()); } catch (Exception e) { result.Throw(e); } }); return(result); } dispatchQueue.QueueWorkItem(() => callback()); return(null); }
/// <summary> /// Signal the RendezVousEvent. If a receiver continuation is present, trigger it. /// Otherwise, store the signal until a continuation is registered. /// </summary> /// <exception cref="InvalidOperationException">The RendezVousEvent instance has already been signaled.</exception> public void Signal() { if (HasCompleted) { throw new InvalidOperationException("event has already been used"); } object value = Interlocked.Exchange(ref _placeholder, TOKEN); if (value != null) { if (!(value is Action)) { throw new InvalidOperationException("event has already been signaled"); } Action handler = (Action)value; Interlocked.Decrement(ref _pendingCounter); if (_captured) { lock (Pending) { Pending.Remove(this); } } _placeholder = USED; if (_dispatchQueue != null) { _dispatchQueue.QueueWorkItem(handler); } else { try { handler(); } catch (Exception e) { // log exception, but ignore it; outer task is immune to it _log.WarnExceptionMethodCall(e, "Signal: unhandled exception in continuation"); } } } }
/// <summary> /// Enqueue a callback as a work item to be invoked with the current <see cref="TaskEnv"/>. /// </summary> /// <param name="dispatchQueue">DispatchQueue to enqueue work into.</param> /// <param name="callback">Work item callback.</param> /// <param name="result">Synchronization handle for work item.</param> /// <returns>The synchronization handle provided to the method.</returns> public static Result QueueWorkItemWithCurrentEnv(this IDispatchQueue dispatchQueue, Action callback, Result result) { var current = TaskEnv.CurrentOrNull; if (current != null) { return(dispatchQueue.QueueWorkItemWithEnv(callback, current, result)); } if (result != null) { dispatchQueue.QueueWorkItem(() => { try { callback(); result.Return(); } catch (Exception e) { result.Throw(e); } }); return(result); } dispatchQueue.QueueWorkItem(callback); return(null); }
public void EvictWorkItems() { // clear CurrentThread to avoid having the evicted items being immediately added back again to the thread (i.e. infinite loop) CurrentThread = null; try { Action item; // remove up to 100 items from the current threads work queue for (int i = 0; (i < 100) && _inbox.TryPop(out item); ++i) { _queue.QueueWorkItem(item); } } finally { // restore CurrentThread before we exit CurrentThread = this; } }
private static Result <int> Fibonacci(IDispatchQueue stp, int n, TimeSpan delay, Result <int> result) { if (!ReferenceEquals(result.Env.DispatchQueue, stp)) { _log.Error(string.Format("ERROR: wrong task env {0}, expected {1}.", result.Env.DispatchQueue, stp)); } stp.QueueWorkItem(delegate { Interlocked.Increment(ref _counter); switch (n) { case 0: if (delay > TimeSpan.Zero) { Thread.Sleep(delay); } result.Return(0); break; case 1: if (delay > TimeSpan.Zero) { Thread.Sleep(delay); } result.Return(1); break; default: Result <int> a = Fibonacci(stp, n - 1, delay, new Result <int>(TimeSpan.MaxValue, TaskEnv.New(stp))); Result <int> b = Fibonacci(stp, n - 2, delay, new Result <int>(TimeSpan.MaxValue, TaskEnv.New(stp))); new AResult[] { a, b }.Join(new Result(TimeSpan.MaxValue, TaskEnv.New(stp))).WhenDone(_ => { if (!ReferenceEquals(AsyncUtil.CurrentDispatchQueue, stp)) { _log.Error(string.Format("ERROR: wrong queue {0}, expected {1}.", AsyncUtil.CurrentDispatchQueue, stp)); } result.Return(a.Value + b.Value); }); break; } }); return(result); }
private static Result<int> Fibonacci(IDispatchQueue stp, int n, TimeSpan delay, Result<int> result) { if(!ReferenceEquals(result.Env.DispatchQueue, stp)) { _log.Error(string.Format("ERROR: wrong task env {0}, expected {1}.", result.Env.DispatchQueue, stp)); } stp.QueueWorkItem(delegate { Interlocked.Increment(ref _counter); switch(n) { case 0: if(delay > TimeSpan.Zero) { Thread.Sleep(delay); } result.Return(0); break; case 1: if(delay > TimeSpan.Zero) { Thread.Sleep(delay); } result.Return(1); break; default: Result<int> a = Fibonacci(stp, n - 1, delay, new Result<int>(TimeSpan.MaxValue, TaskEnv.New(stp))); Result<int> b = Fibonacci(stp, n - 2, delay, new Result<int>(TimeSpan.MaxValue, TaskEnv.New(stp))); new AResult[] { a, b }.Join(new Result(TimeSpan.MaxValue, TaskEnv.New(stp))).WhenDone(_ => { if(!ReferenceEquals(Async.CurrentDispatchQueue, stp)) { _log.Error(string.Format("ERROR: wrong queue {0}, expected {1}.", Async.CurrentDispatchQueue, stp)); } result.Return(a.Value + b.Value); }); break; } }); return result; }