Ejemplo n.º 1
0
        /// <summary>
        /// Disposes of the registration and unregisters the target callback from the associated
        /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see>.
        /// If the target callback is currently executing this method will wait until it completes, except
        /// in the degenerate cases where a callback method deregisters itself.
        /// </summary>
        public void Dispose()
        {
            // If the token source has been disposed, we must throw.
            if (m_tokenSource != null)
            {
                m_tokenSource.ThrowIfDisposed();
            }

            // Remove the entry from the array.
            // This call includes a full memory fence which prevents potential reorderings of the reads below
            bool deregisterOccured = TryDeregister();

            // We guarantee that we will not return if the callback is being executed (assuming we are not currently called by the callback itself)
            // We achieve this by the following rules:
            //    1. if we are called in the context of an executing callback, no need to wait (determined by tracking callback-executor threadID)
            //       - if the currently executing callback is this CTR, then waiting would deadlock. (We choose to return rather than deadlock)
            //       - if not, then this CTR cannot be the one executing, hence no need to wait
            //
            //    2. if deregistration failed, and we are on a different thread, then the callback may be running under control of cts.Cancel()
            //       => poll until cts.ExecutingCallback is not the one we are trying to deregister.

            if (m_tokenSource != null &&
                m_tokenSource.IsCancellationRequested &&                                          //running callbacks has commenced.
                !m_tokenSource.IsCancellationCompleted &&                                         //running callbacks hasn't finished
                !deregisterOccured &&                                                             //deregistration failed (ie the callback is missing from the list)
                m_tokenSource.ThreadIDExecutingCallbacks != Thread.CurrentThread.ManagedThreadId) //the executingThreadID is not this threadID.
            {
                // Callback execution is in progress, the executing thread is different to us and has taken the callback for execution
                // so observe and wait until this target callback is no longer the executing callback.
                m_tokenSource.WaitForCallbackToComplete(m_callbackInfo);
            }
        }
Ejemplo n.º 2
0
        public void Dispose()
        {
            bool flag = this.TryDeregister();
            CancellationCallbackInfo callbackInfo = this.m_callbackInfo;

            if (callbackInfo != null)
            {
                CancellationTokenSource cancellationTokenSource = callbackInfo.CancellationTokenSource;
                if (cancellationTokenSource.IsCancellationRequested && !cancellationTokenSource.IsCancellationCompleted && !flag && cancellationTokenSource.ThreadIDExecutingCallbacks != Thread.CurrentThread.ManagedThreadId)
                {
                    cancellationTokenSource.WaitForCallbackToComplete(this.m_callbackInfo);
                }
            }
        }
        public void Dispose()
        {
            bool flag = this.TryDeregister();
            CancellationCallbackInfo cancellationCallbackInfo = this.m_callbackInfo;

            if (cancellationCallbackInfo == null)
            {
                return;
            }
            CancellationTokenSource cancellationTokenSource = cancellationCallbackInfo.CancellationTokenSource;

            if (!cancellationTokenSource.IsCancellationRequested || cancellationTokenSource.IsCancellationCompleted || (flag || cancellationTokenSource.ThreadIDExecutingCallbacks == Thread.CurrentThread.ManagedThreadId))
            {
                return;
            }
            cancellationTokenSource.WaitForCallbackToComplete(this.m_callbackInfo);
        }
Ejemplo n.º 4
0
 private void WaitForCallbackIfNecessary()
 {
     // We're a valid registration but we were unable to unregister, which means the callback wasn't in the list,
     // which means either it already executed or it's currently executing. We guarantee that we will not return
     // if the callback is being executed (assuming we are not currently called by the callback itself)
     // We achieve this by the following rules:
     //    1. If we are called in the context of an executing callback, no need to wait (determined by tracking callback-executor threadID)
     //       - if the currently executing callback is this CTR, then waiting would deadlock. (We choose to return rather than deadlock)
     //       - if not, then this CTR cannot be the one executing, hence no need to wait
     //    2. If unregistration failed, and we are on a different thread, then the callback may be running under control of cts.Cancel()
     //       => poll until cts.ExecutingCallback is not the one we are trying to unregister.
     CancellationTokenSource source = _node.Partition.Source;
     if (source.IsCancellationRequested && // Running callbacks has commenced.
         !source.IsCancellationCompleted && // Running callbacks hasn't finished.
         source.ThreadIDExecutingCallbacks != Environment.CurrentManagedThreadId) // The executing thread ID is not this thread's ID.
     {
         // Callback execution is in progress, the executing thread is different from this thread and has taken the callback for execution
         // so observe and wait until this target callback is no longer the executing callback.
         source.WaitForCallbackToComplete(_id);
     }
 }