private void ShutdownImpl() { Debug.Assert(_hasShutdownStarted); Debug.Assert(!_hasShutdownFinished); // Call the ShutdownFinished event before we actually mark ourselves // as shut down. This is so the handlers can actaully do work // when they get this event without throwing exceptions. EventHandler e = ShutdownFinished; if (e != null) { e(this, EventArgs.Empty); } // Mark this dispatcher as shut down. Attempts to BeginInvoke // or Invoke will result in an exception. _hasShutdownFinished = true; lock (_instanceLock) { // Now that the queue is off-line, abort all pending operations, // including inactive ones. while (_queue.Count > 0) { DispatcherOperation operation = (DispatcherOperation)_queue.Dequeue(); if (operation != null) { operation.Abort(); } } } }
/// <summary> /// Executes the specified delegate synchronously with the specified /// arguments, on the thread that the Dispatcher was created on. /// </summary> /// <param name="timeout"> /// The maximum amount of time to wait for the operation to complete. /// </param> /// <param name="method"> /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// </param> /// <param name="args"> /// An object to pass as the argument to the given method. /// This can be null if no arguments are needed. /// </param> /// <returns> /// The return value from the delegate being invoked, or null if /// the delegate has no return value or if the operation was aborted. /// </returns> public object Invoke(TimeSpan timeout, DispatcherOperationCallback method, object args) { if (method == null) { throw new ArgumentNullException("method"); } object result = null; DispatcherOperation op = BeginInvoke(method, args); if (op != null) { op.Wait(timeout); if (op.Status == DispatcherOperationStatus.Completed) { result = op.Result; } else if (op.Status == DispatcherOperationStatus.Aborted) { // Hm, someone aborted us. Maybe the dispatcher got // shut down on us? Just return null. } else { // We timed out, just abort the op so that it doesn't // invoke later. // // Note the race condition: if this is a foreign thread, // it is possible that the dispatcher thread could actually // dispatch the operation between the time our Wait() // call returns and we get here. In the case the operation // will actually be dispatched, but we will return failure. // // We recognize this but decide not to do anything about it, // as this is a common problem is multi-threaded programming. op.Abort(); } } return(result); }