Exemplo n.º 1
0
        internal CancellationTokenRegistration Register(Action callback, bool useSynchronizationContext)
        {
            CheckDisposed();

            var tokenReg = new CancellationTokenRegistration(CustomInterlocked.Increment(ref currId), this);

            /* If the source is already canceled we execute the callback immediately
             * if not, we try to add it to the queue and if it is currently being processed
             * we try to execute it back ourselves to be sure the callback is ran
             */
            if (IsCancellationRequested)
            {
                callback();
            }
            else
            {
                callbacks.TryAdd(tokenReg, callback);
                if (IsCancellationRequested && callbacks.TryRemove(tokenReg, out callback))
                {
                    callback();
                }
            }

            return(tokenReg);
        }
        void CommitChangeToHandle(long stamp)
        {
            CustomInterlocked.Increment(ref used);
            var tmpHandle = Handle;

            if (tmpHandle != null)
            {
                // First in all case we carry the operation we were called for
                if ((stamp & 1) == 1)
                {
                    tmpHandle.Set();
                }
                else
                {
                    tmpHandle.Reset();
                }

                /* Then what may happen is that the two suboperations (state change and handle change)
                 * overlapped with others. In our case it doesn't matter if the two suboperations aren't
                 * executed together at the same time, the only thing we have to make sure of is that both
                 * state and handle are synchronized on the last visible state change.
                 *
                 * For instance if S is state change and H is handle change, for 3 concurrent operations
                 * we may have the following serialized timeline: S1 S2 H2 S3 H3 H1
                 * Which is perfectly fine (all S were converted to H at some stage) but in that case
                 * we have a mismatch between S and H at the end because the last operations done were
                 * S3/H1. We thus need to repeat H3 to get to the desired final state.
                 */
                int currentState;
                do
                {
                    currentState = state;
                    if (currentState != stamp && (stamp & 1) != (currentState & 1))
                    {
                        if ((currentState & 1) == 1)
                        {
                            tmpHandle.Set();
                        }
                        else
                        {
                            tmpHandle.Reset();
                        }
                    }
                } while (currentState != state);
            }
            CustomInterlocked.Decrement(ref used);
        }