/// <summary>A wrapper over DispatchSync that calls a value-producing function and returns it's result</summary> /// <typeparam name="T">Result type</typeparam> /// <param name="queue">The queue to execute the function on</param> /// <param name="func">The function to execute</param> /// <returns>The return value of func</returns> public static T DispatchSync <T>(this IDispatchQueue queue, Func <T> func) { T result = default(T); queue.DispatchSync(() => { result = func(); }); return(result); }
//--- Constructors --- /// <summary> /// Create an instance of the work queue. /// </summary> /// <param name="handler">Dispatch action for work item Type and with completion callback.</param> /// <param name="maxParallelism">Maximum number of items being dispatch simultaneously against the dispatch queue.</param> /// <param name="dispatchQueue">Dispatch queue for work items.</param> public ProcessingQueue(Action <T, Action> handler, int maxParallelism, IDispatchQueue dispatchQueue) { if (dispatchQueue == null) { throw new ArgumentNullException("dispatchQueue"); } if (handler == null) { throw new ArgumentNullException("handler"); } if ((maxParallelism <= 0) || (maxParallelism > MAX_PARALLELISM)) { throw new ArgumentException(string.Format("maxParallelism must be between 1 and {0:#,##0}", MAX_PARALLELISM), "maxParallelism"); } _handler = handler; _dispatchQueue = dispatchQueue; // prime the pending queue with dispatchers for (var i = 0; i < maxParallelism; ++i) { if (!_pending.TryEnqueue(StartWorkItem)) { throw new NotSupportedException(); } } }
//init public DirectSignalProvider(IEventQueue <TKey> eventQueues, IDispatchQueue <TKey> dispatchQueues, IMonitor <TKey> eventSink, ISignalEventQueries <TKey> eventQueries, ISignalDispatchQueries <TKey> dispatchQueries, SenderSettings senderSettings) : base(eventQueues, dispatchQueues, eventSink, eventQueries, dispatchQueries, senderSettings) { _isStarted = false; }
//ctor public SendDispatchCommand(IDispatchChannelRegistry <TKey> channelRegistry, ILogger logger, IDispatchQueue <TKey> dispatchQueue, IMonitor <TKey> monitor) { _channelRegistry = channelRegistry; _logger = logger; _dispatchQueue = dispatchQueue; _monitor = monitor; }
/// <summary> /// Create a new environment. /// </summary> /// <param name="dispatchQueue">Dispatch queue to use for the environment.</param> /// <param name="taskTimerFactory"><see cref="TaskTimer"/> factory to use for the environment.</param> /// <returns>A new <see cref="TaskEnv"/> instance.</returns> public static TaskEnv New(IDispatchQueue dispatchQueue, TaskTimerFactory taskTimerFactory) { if (dispatchQueue == null) { throw new ArgumentNullException("dispatchQueue"); } return(new TaskEnv(dispatchQueue, taskTimerFactory)); }
public DatabaseDispatchProvider(IDispatchQueue <TKey> dispatchQueues, IMonitor <TKey> eventSink, SenderSettings senderSettings, IDispatchChannelRegistry <TKey> dispatcherRegistry, ISignalDispatchQueries <TKey> dispatchQueries, ILogger logger, IChangeNotifier <SignalDispatch <TKey> > changeNotifier, ILockTracker <TKey> lockTracker, IConsolidationLockTracker <TKey> consolidationLockTracker) : this(dispatchQueues, eventSink, senderSettings, dispatcherRegistry, dispatchQueries, logger, lockTracker, consolidationLockTracker) { _changeNotifier = changeNotifier; }
/// <summary> /// Clone the current task environment with a provided dispatch queue. /// </summary> /// <param name="dispatchQueue">Dispatch queue to use for the environment.</param> /// <returns>A new <see cref="TaskEnv"/> instance.</returns> public static TaskEnv Clone(IDispatchQueue dispatchQueue) { if (dispatchQueue == null) { throw new ArgumentNullException("dispatchQueue"); } return(new TaskEnv(_currentEnv, dispatchQueue, CurrentTimerFactoryOrNull)); }
public TimerQueue(IDispatchQueue dispatchQueue, IDispatcher dispatcher) { mDispatchQueue = dispatchQueue ?? throw new ArgumentNullException("dispatchQueue"); mDispatcher = dispatcher ?? throw new ArgumentNullException("dispatcher"); mTimer = new Timer(OnTimerExecute); mScheduleWorkForExecutionCallback = OnScheduleWorkForExecution; }
//ctor public CheckConsolidationLockExpirationCommand(IConsolidationLockTracker <TKey> lockTracker, IConsolidationLockQueries <TKey> consolidationLockQueries, SenderSettings settings, IDispatchQueue <TKey> dispatchQueue) { _consolidationLockTracker = lockTracker; _consolidationLockQueries = consolidationLockQueries; _settings = settings; _dispatchQueue = dispatchQueue; }
/// <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); }
public void PinTo(IDispatchQueue dispatchQueue) { // TODO 2.0 (steveb): remove implementation if (_dispatchQueue != null) { throw new InvalidOperationException("RendezVousEvent is already pinned to an IDispatchQueue"); } _dispatchQueue = dispatchQueue; }
//init public BaseSignalProvider(IEventQueue <TKey> eventQueue, IDispatchQueue <TKey> dispatchQueue, IMonitor <TKey> eventSink, ISignalEventQueries <TKey> eventQueries, ISignalDispatchQueries <TKey> dispatchQueries, SenderSettings senderSettings) { _eventQueue = eventQueue; _dispatchQueue = dispatchQueue; _monitor = eventSink; _eventQueries = eventQueries; _dispatchQueries = dispatchQueries; _senderSettings = senderSettings; }
//ctor public ConsolidateDispatchCommand(ILogger logger, ISignalDispatchQueries <TKey> signalDispatchQueries, IDispatchQueue <TKey> dispatchQueue, IEnumerable <ITemplateDataConsolidator> consolidators, IEventSettingsQueries <TKey> eventSettingsQueries) { _logger = logger; _signalDispatchQueries = signalDispatchQueries; _dispatchQueue = dispatchQueue; _consolidators = consolidators.ToArray(); _eventSettingsQueries = eventSettingsQueries; }
private static void FibonacciThreadPool(IDispatchQueue stp, int n, TimeSpan delay, out int value, out TimeSpan elapsed) { _log.Debug("FibonacciThreadPool"); var sw = Stopwatch.StartNew(); value = Fibonacci(stp, n, delay, new Result <int>(TimeSpan.MaxValue, TaskEnv.New(stp))).Wait(); sw.Stop(); elapsed = sw.Elapsed; }
//init public SignalServiceInstanceProvider(IEventQueue <TKey> eventQueues, IDispatchQueue <TKey> dispatchQueues, IMonitor <TKey> eventSink, ISignalEventQueries <TKey> eventQueries, ISignalDispatchQueries <TKey> dispatchQueries, SenderSettings senderSettings) { _eventQueues = eventQueues; _dispatchQueues = dispatchQueues; _monitor = eventSink; _eventQueries = eventQueries; _dispatchQueries = dispatchQueries; _senderSettings = senderSettings; }
//--- Class Methods --- public static bool TryQueueWorkItem(IDispatchQueue queue, Action callback) { DispatchThread current = CurrentThread; if ((current != null) && ReferenceEquals(AsyncUtil.CurrentDispatchQueue, queue)) { // NOTE (steveb): next call can never fail since we're calling the queue work-item method of the current thread current.QueueWorkItem(callback); return(true); } return(false); }
public static void DispatchSync(this IDispatchQueue queue, object?context, WaitCallback?work) { TaskCompletionSource <object?> tcs = new TaskCompletionSource <object?>(); queue.DispatchAsync(context, (context) => { work?.Invoke(context); tcs.SetResult(null); }); tcs.Task.Wait(); }
private TaskEnv(TaskEnv env, IDispatchQueue dispatchQueue, TaskTimerFactory taskTimerFactory) { if (env != null) { foreach (var entry in env) { var cloneable = entry.Value as ITaskLifespan; Add(entry.Key, cloneable == null ? entry.Value : cloneable.Clone()); } } _taskTimerFactory = taskTimerFactory; _dispatchQueue = (dispatchQueue is ImmediateDispatchQueue) ? null : dispatchQueue; }
/// <summary>A wrapper over DispatchAsync that calls a value-producing function on the queue and returns it's result via a Task</summary> /// <remarks>Note: the task "completes" on the dispatch queue, so if you use ConfigureAwait(false) or /// TaskContinuationOptions.ExecuteSychronously, you will still be running on the dispatch queue</remarks> /// <typeparam name="T">Result type</typeparam> /// <param name="queue">The queue to execute the function on</param> /// <param name="func">The function to execute</param> /// <returns>A task wrapping the return value (or exception) the func produced.</returns> public static Task <T> DispatchAsync <T>(this IDispatchQueue queue, Func <T> func) { var tcs = new TaskCompletionSource <T>(); queue.DispatchAsync(() => { try { tcs.SetResult(func()); } catch (Exception e) { tcs.TrySetException(e); } }); return(tcs.Task); }
//init public DispatchProcessor(SenderState <TKey> hubState, IDispatchQueue <TKey> dispatchQueue, ILogger logger, SenderSettings senderSettings, IDispatchChannelRegistry <TKey> channelRegistry, IEnumerable <IDispatchProcessingCommand <TKey> > processingCommands) : base(logger) { _hubState = hubState; _dispatchQueue = dispatchQueue; _channelRegistry = channelRegistry; _processingCommands = processingCommands .OrderBy(x => x.Order) .ToArray(); MaxParallelItems = senderSettings.MaxParallelDispatchesProcessed; }
//init public EventProcessor(SenderState <TKey> hubState, IMonitor <TKey> eventSink , ILogger logger, SenderSettings senderSettings , IEventQueue <TKey> eventQueue, IDispatchQueue <TKey> dispatchQueue , IEventHandlerRegistry <TKey> handlerRegistry, IEventSettingsQueries <TKey> eventSettingsQueries) : base(logger) { _hubState = hubState; _monitor = eventSink; _eventQueue = eventQueue; _dispatchQueue = dispatchQueue; _handlerRegistry = handlerRegistry; _eventSettingsQueries = eventSettingsQueries; MaxParallelItems = senderSettings.MaxParallelEventsProcessed; }
public NewRoomRequestHandler( IDispatchQueue centralDispatchQueue, IRoomRepository roomRepository, IRoomFactory roomFactory, IObserver <TransceiverMetadataUpdatedEvent> transceiverMetadataUpdatedObserver) { _centralDispatchQueue = centralDispatchQueue ?? throw new ArgumentNullException(nameof(centralDispatchQueue)); _roomRepository = roomRepository ?? throw new ArgumentNullException(nameof(roomRepository)); _roomFactory = roomFactory ?? throw new ArgumentNullException(nameof(roomFactory)); _transceiverMetadataUpdatedObserver = transceiverMetadataUpdatedObserver ?? throw new ArgumentNullException(nameof(transceiverMetadataUpdatedObserver)); }
//--- Constructors --- static Async() { if (!int.TryParse(System.Configuration.ConfigurationManager.AppSettings["threadpool-min"], out _minThreads)) { _minThreads = 4; } if (!int.TryParse(System.Configuration.ConfigurationManager.AppSettings["threadpool-max"], out _maxThreads)) { _maxThreads = 200; } int maxStackSize; if (int.TryParse(System.Configuration.ConfigurationManager.AppSettings["max-stacksize"], out maxStackSize)) { _maxStackSize = maxStackSize; } // check which global dispatch queue implementation to use int dummy; switch (System.Configuration.ConfigurationManager.AppSettings["threadpool"]) { default: case "elastic": ThreadPool.GetMinThreads(out dummy, out _minPorts); ThreadPool.GetMaxThreads(out dummy, out _maxPorts); _log.DebugFormat("Using ElasticThreadPool with {0}min / {1}max", _minThreads, _maxThreads); var elasticThreadPool = new ElasticThreadPool(_minThreads, _maxThreads); GlobalDispatchQueue = elasticThreadPool; _inplaceActivation = false; _availableThreadsCallback = delegate(out int threads, out int ports) { int dummy2; ThreadPool.GetAvailableThreads(out dummy2, out ports); threads = elasticThreadPool.MaxParallelThreads - elasticThreadPool.ThreadCount; }; break; case "legacy": ThreadPool.GetMinThreads(out dummy, out _minPorts); ThreadPool.GetMaxThreads(out dummy, out _maxPorts); ThreadPool.SetMinThreads(_minThreads, _minPorts); ThreadPool.SetMaxThreads(_maxThreads, _maxPorts); _log.Debug("Using LegacyThreadPool"); GlobalDispatchQueue = LegacyThreadPool.Instance; _availableThreadsCallback = ThreadPool.GetAvailableThreads; break; } }
//init public Sender(SenderState <TKey> hubState, IEventQueue <TKey> eventQueue, IDispatchQueue <TKey> dispatchQueue, IEnumerable <IRegularJob> regularJobs, IEnumerable <ISignalProviderControl> signalEndpoints) { _hubState = hubState; _regularJobs = regularJobs.ToList(); _eventQueue = eventQueue; _dispatchQueue = dispatchQueue; _signalEndpoints = signalEndpoints.ToList(); _regularJobTimers = _regularJobs.Select(x => new NonReentrantTimer(x.Tick , NotificationsConstants.REGULAR_JOB_TICK_INTERVAL, intervalFromCallbackStarted: false)) .ToList(); _stopMonitorTimer = new NonReentrantTimer(StopTimers , NotificationsConstants.REGULAR_JOB_TICK_INTERVAL, intervalFromCallbackStarted: false); _stopEventHandle = new ManualResetEventSlim(false); }
//init public DatabaseDispatchProvider(IDispatchQueue <TKey> dispatchQueue, IMonitor <TKey> eventSink, SenderSettings senderSettings, IDispatchChannelRegistry <TKey> dispatcherRegistry, ISignalDispatchQueries <TKey> dispatchQueries, ILogger logger, ILockTracker <TKey> lockTracker, IConsolidationLockTracker <TKey> consolidationLockTracker) { _dispatchQueue = dispatchQueue; _monitor = eventSink; _dispatcherRegistry = dispatcherRegistry; _dispatchQueries = dispatchQueries; _logger = logger; _lockTracker = lockTracker; _consolidationLockTracker = consolidationLockTracker; _senderSettings = senderSettings; QueryPeriod = senderSettings.DatabaseSignalProviderQueryPeriod; ItemsQueryCount = senderSettings.DatabaseSignalProviderItemsQueryCount; MaxFailedAttempts = senderSettings.DatabaseSignalProviderItemsMaxFailedAttempts; }
// (yurig): This method has been intentionally split from DispatchLoop() // result.Block() inside causes Result<DispatchWorkItem> to never be disposed. // By moving it into its own method we ensure its garbage collection as it is // popped off the stack. Do NOT inline this method into DispatchLoop(). private bool GetNextWorkItem(out Action callback) { if (!_inbox.TryPop(out callback)) { var result = new Result <DispatchWorkItem>(TimeSpan.MaxValue); // reset the dispatch queue for this thread AsyncUtil.CurrentDispatchQueue = null; _queue = null; // check if thread is associated with a host already if (_host == null) { // NOTE (steveb): this is a brand new thread without a host yet // return the thread to the dispatch scheduler DispatchThreadScheduler.ReleaseThread(this, result); } else { // request another work-item _host.RequestWorkItem(this, result); } // block until a work item is available result.Block(); // check if we received a work item or an exception to shutdown if (result.HasException && (result.Exception is DispatchThreadShutdownException)) { // time to shut down _log.DebugFormat("DispatchThread #{0} destroyed", _id); return(false); } callback = result.Value.WorkItem; _queue = result.Value.DispatchQueue; // TODO (steveb): handle the weird case where _queue is null // set the dispatch queue for this thread AsyncUtil.CurrentDispatchQueue = _queue; } return(true); }
private bool TryQueueWorkItem(int priority, Action callback) { if (_disposed) { throw new ObjectDisposedException("ElasticThreadPool has already been disposed"); } // check if we can enqueue work-item into current dispatch thread IDispatchQueue queue = this[priority]; if (DispatchThread.TryQueueWorkItem(queue, callback)) { return(true); } // check if there are available threads to which the work-item can be given to KeyValuePair <DispatchThread, Result <DispatchWorkItem> > entry; if (_reservedThreads.TryPop(out entry)) { lock (_syncRoot) { RegisterThread("new item", entry.Key); } // found an available thread, let's resume it with the work-item entry.Value.Return(new DispatchWorkItem(callback, queue)); return(true); } // no threads available, keep work-item for later if (!_inbox.TryEnqueue(priority, callback)) { return(false); } // check if we need to request a thread to kick things off if (ThreadCount == 0) { ((IDispatchHost)this).IncreaseThreadCount("request first thread"); } return(true); }
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); }
/// <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> /// 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); }
//--- Constructors --- /// <summary> /// Create new work-item instance. /// </summary> /// <param name="workitem">Work-item callback.</param> /// <param name="queue">Dispatch queue associated with work-item.</param> public DispatchWorkItem(Action workitem, IDispatchQueue queue) { this.WorkItem = workitem; this.DispatchQueue = queue; }
private static void FibonacciThreadPool(IDispatchQueue stp, int n, TimeSpan delay, out int value, out TimeSpan elapsed) { _log.Debug("FibonacciThreadPool"); var sw = Stopwatch.StartNew(); value = Fibonacci(stp, n, delay, new Result<int>(TimeSpan.MaxValue, TaskEnv.New(stp))).Wait(); sw.Stop(); elapsed = sw.Elapsed; }
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; }
public void PinTo(IDispatchQueue dispatchQueue) { // TODO 2.0 (steveb): remove implementation if(_dispatchQueue != null) { throw new InvalidOperationException("RendezVousEvent is already pinned to an IDispatchQueue"); } _dispatchQueue = dispatchQueue; }
// (yurig): This method has been intentionally split from DispatchLoop() // result.Block() inside causes Result<DispatchWorkItem> to never be disposed. // By moving it into its own method we ensure its garbage collection as it is // popped off the stack. Do NOT inline this method into DispatchLoop(). private bool GetNextWorkItem(out Action callback) { if(!_inbox.TryPop(out callback)) { var result = new Result<DispatchWorkItem>(TimeSpan.MaxValue); // reset the dispatch queue for this thread AsyncUtil.CurrentDispatchQueue = null; _queue = null; // check if thread is associated with a host already if(_host == null) { // NOTE (steveb): this is a brand new thread without a host yet // return the thread to the dispatch scheduler DispatchThreadScheduler.ReleaseThread(this, result); } else { // request another work-item _host.RequestWorkItem(this, result); } // block until a work item is available result.Block(); // check if we received a work item or an exception to shutdown if(result.HasException && (result.Exception is DispatchThreadShutdownException)) { // time to shut down _log.DebugFormat("DispatchThread #{0} destroyed", _id); return false; } callback = result.Value.WorkItem; _queue = result.Value.DispatchQueue; // TODO (steveb): handle the weird case where _queue is null // set the dispatch queue for this thread AsyncUtil.CurrentDispatchQueue = _queue; } return true; }
private void DispatchLoop() { // set thread-local self-reference CurrentThread = this; // begin thread loop try { while(true) { // check if queue has a work-item Action callback; if(!_inbox.TryPop(out callback)) { var result = new Result<DispatchWorkItem>(TimeSpan.MaxValue); // reset the dispatch queue for this thread Async.CurrentDispatchQueue = null; // check if thread is associated with a host already if(_host == null) { // NOTE (steveb): this is a brand new thread without a host yet // return the thread to the dispatch scheduler DispatchThreadScheduler.ReleaseThread(this, result); } else { // request another work-item _host.RequestWorkItem(this, result); } // block until a work item is available result.Block(); // check if we received a work item or an exception to shutdown if(result.HasException && (result.Exception is DispatchThreadShutdownException)) { // time to shut down _log.DebugFormat("DispatchThread #{0} destroyed", _id); return; } callback = result.Value.WorkItem; _queue = result.Value.DispatchQueue; // TODO (steveb): handle the weird case where _queue is null // set the dispatch queue for this thread Async.CurrentDispatchQueue = _queue; } // execute work-item if(callback != null) { try { callback(); } catch(Exception e) { _log.Warn("an unhandled exception occurred while executing the work-item", e); } } } } catch(Exception e) { // something went wrong that shouldn't have! _log.ErrorExceptionMethodCall(e, string.Format("DispatchLoop #{0}: FATAL ERROR", _id)); // TODO (steveb): tell _host about untimely exit; post items in queue to host inbox (o/w we lose them) } finally { CurrentThread = null; } }
//--- Class Methods --- public static bool TryQueueWorkItem(IDispatchQueue queue, Action callback) { DispatchThread current = CurrentThread; if((current != null) && ReferenceEquals(Async.CurrentDispatchQueue, queue)) { // NOTE (steveb): next call can never fail since we're calling the queue work-item method of the current thread current.QueueWorkItem(callback); return true; } return false; }