CompareExchange() 개인적인 메소드

private CompareExchange ( int &location1, int value, int comparand ) : int
location1 int
value int
comparand int
리턴 int
예제 #1
0
파일: ConcurrentList.cs 프로젝트: Nucs/nlib
        public override void Add(T element)
        {
            int index         = Interlocked.Increment(ref _index) - 1;
            int adjustedIndex = index;

            int arrayIndex = GetArrayIndex(index + 1);

            if (arrayIndex > 0)
            {
                adjustedIndex -= Counts[arrayIndex - 1];
            }

            if (_array[arrayIndex] == null)
            {
                int arrayLength = Sizes[arrayIndex];
                Interlocked.CompareExchange(ref _array[arrayIndex], new T[arrayLength], null);
            }

            _array[arrayIndex][adjustedIndex] = element;

            int count      = _count;
            int fuzzyCount = Interlocked.Increment(ref _fuzzyCount);

            if (fuzzyCount == index + 1)
            {
                Interlocked.CompareExchange(ref _count, fuzzyCount, count);
            }
            ItemAddedEvent?.Invoke(element, index);
        }
예제 #2
0
        public override T this[int key]
        {
            get
            {
                if (key < minIndex || key > maxIndex)
                {
                    return(null);
                }

#if NET45PLUS
                return(Volatile.Read(ref arrayData[key - minIndex]));
#else
                return(Interlocked.CompareExchange(ref arrayData[key - minIndex], null, null));
#endif
            }
        }
예제 #3
0
            /// <summary>
            /// Attempt to add "value" to the table, hashed by an embedded string key.  If a value having the same key already exists,
            /// then return the existing value in "newValue".  Otherwise, return the newly added value in "newValue".
            ///
            /// If the hash table is full, return false.  Otherwise, return true.
            /// </summary>
            public bool TryAdd(TValue value, out TValue newValue)
            {
                int    newEntry, entryIndex;
                string key;
                int    hashCode;

                // Assume "value" will be added and returned as "newValue"
                newValue = value;

                // Extract the key from the value.  If it's null, then value is invalid and does not need to be added to table.
                key = _extractKey(value);
                if (key == null)
                {
                    return(true);
                }

                // Compute hash code over entire length of key
                hashCode = ComputeHashCode(key, 0, key.Length);

                // Assume value is not yet in the hash table, and prepare to add it (if table is full, return false).
                // Use the entry index returned from Increment, which will never be zero, as zero conflicts with EndOfList.
                // Although this means that the first entry will never be used, it avoids the need to initialize all
                // starting buckets to the EndOfList value.
                newEntry = Interlocked.Increment(ref _numEntries);
                if (newEntry < 0 || newEntry >= _buckets.Length)
                {
                    return(false);
                }

                _entries[newEntry].Value    = value;
                _entries[newEntry].HashCode = hashCode;

                // Ensure that all writes to the entry can't be reordered past this barrier (or other threads might see new entry
                // in list before entry has been initialized!).
                Thread.MemoryBarrier();

                // Loop until a matching entry is found, a new entry is added, or linked list is found to be full
                entryIndex = 0;
                while (!FindEntry(hashCode, key, 0, key.Length, ref entryIndex))
                {
                    // PUBLISH (buckets slot)
                    // No matching entry found, so add the new entry to the end of the list ("entryIndex" is index of last entry)
                    if (entryIndex == 0)
                    {
                        entryIndex = Interlocked.CompareExchange(ref _buckets[hashCode & (_buckets.Length - 1)], newEntry, EndOfList);
                    }
                    else
                    {
                        entryIndex = Interlocked.CompareExchange(ref _entries[entryIndex].Next, newEntry, EndOfList);
                    }

                    // Return true only if the CompareExchange succeeded (happens when replaced value is EndOfList).
                    // Return false if the linked list turned out to be full because another thread is currently resizing
                    // the hash table.  In this case, entries[newEntry] is orphaned (not part of any linked list) and the
                    // Add needs to be performed on the new hash table.  Otherwise, keep looping, looking for new end of list.
                    if (entryIndex <= EndOfList)
                    {
                        return(entryIndex == EndOfList);
                    }
                }

                // Another thread already added the value while this thread was trying to add, so return that instance instead.
                // Note that entries[newEntry] will be orphaned (not part of any linked list) in this case
                newValue = _entries[entryIndex].Value;

                return(true);
            }
예제 #4
0
            /// <summary>
            /// If this table is not full, then just return "this".  Otherwise, create and return a new table with
            /// additional capacity, and rehash all values in the table.
            /// </summary>
            public XHashtableState Resize()
            {
                // No need to resize if there are open entries
                if (_numEntries < _buckets.Length)
                {
                    return(this);
                }

                int newSize = 0;

                // Determine capacity of resized hash table by first counting number of valid, non-orphaned entries
                // As this count proceeds, close all linked lists so that no additional entries can be added to them
                for (int bucketIdx = 0; bucketIdx < _buckets.Length; bucketIdx++)
                {
                    int entryIdx = _buckets[bucketIdx];

                    if (entryIdx == EndOfList)
                    {
                        // Replace EndOfList with FullList, so that any threads still attempting to add will be forced to resize
                        entryIdx = Interlocked.CompareExchange(ref _buckets[bucketIdx], FullList, EndOfList);
                    }

                    // Loop until we've guaranteed that the list has been counted and closed to further adds
                    while (entryIdx > EndOfList)
                    {
                        // Count each valid entry
                        if (_extractKey(_entries[entryIdx].Value) != null)
                        {
                            newSize++;
                        }

                        if (_entries[entryIdx].Next == EndOfList)
                        {
                            // Replace EndOfList with FullList, so that any threads still attempting to add will be forced to resize
                            entryIdx = Interlocked.CompareExchange(ref _entries[entryIdx].Next, FullList, EndOfList);
                        }
                        else
                        {
                            // Move to next entry in the list
                            entryIdx = _entries[entryIdx].Next;
                        }
                    }
                    Debug.Assert(entryIdx == EndOfList, "Resize() should only be called by one thread");
                }

                // Double number of valid entries; if result is less than current capacity, then use current capacity
                if (newSize < _buckets.Length / 2)
                {
                    newSize = _buckets.Length;
                }
                else
                {
                    newSize = _buckets.Length * 2;

                    if (newSize < 0)
                    {
                        throw new OverflowException();
                    }
                }

                // Create new hash table with additional capacity
                XHashtableState newHashtable = new XHashtableState(_extractKey, newSize);

                // Rehash names (TryAdd will always succeed, since we won't fill the new table)
                // Do not simply walk over entries and add them to table, as that would add orphaned
                // entries.  Instead, walk the linked lists and add each name.
                for (int bucketIdx = 0; bucketIdx < _buckets.Length; bucketIdx++)
                {
                    int    entryIdx = _buckets[bucketIdx];
                    TValue newValue;

                    while (entryIdx > EndOfList)
                    {
                        newHashtable.TryAdd(_entries[entryIdx].Value, out newValue);

                        entryIdx = _entries[entryIdx].Next;
                    }
                    Debug.Assert(entryIdx == FullList, "Linked list should have been closed when it was counted");
                }

                return(newHashtable);
            }
예제 #5
0
파일: Interlocked.cs 프로젝트: rivy/corert
 public static long Read(ref long location)
 {
     return(Interlocked.CompareExchange(ref location, 0, 0));
 }
예제 #6
0
        private bool TryAcquireContended(int currentThreadId, int millisecondsTimeout)
        {
            //
            // If we already own the lock, just increment the recursion count.
            //
            if (_owningThreadId == currentThreadId)
            {
                checked { _recursionCount++; }
                return(true);
            }

            //
            // We've already made one lock attempt at this point, so bail early if the timeout is zero.
            //
            if (millisecondsTimeout == 0)
            {
                return(false);
            }

            int spins = 1;

            if (s_maxSpinCount < 0)
            {
                s_maxSpinCount = (Environment.ProcessorCount > 1) ? 10000 : 0;
            }

            while (true)
            {
                //
                // Try to grab the lock.  We may take the lock here even if there are existing waiters.  This creates the possibility
                // of starvation of waiters, but it also prevents lock convoys from destroying perf.
                // The starvation issue is largely mitigated by the priority boost the OS gives to a waiter when we set
                // the event, after we release the lock.  Eventually waiters will be boosted high enough to preempt this thread.
                //
                int oldState = _state;
                if ((oldState & Locked) == 0 && Interlocked.CompareExchange(ref _state, oldState | Locked, oldState) == oldState)
                {
                    goto GotTheLock;
                }

                //
                // Back off by a factor of 2 for each attempt, up to MaxSpinCount
                //
                if (spins <= s_maxSpinCount)
                {
                    System.Runtime.RuntimeImports.RhSpinWait(spins);
                    spins *= 2;
                }
                else
                {
                    //
                    // We reached our spin limit, and need to wait.  Increment the waiter count.
                    // Note that we do not do any overflow checking on this increment.  In order to overflow,
                    // we'd need to have about 1 billion waiting threads, which is inconceivable anytime in the
                    // forseeable future.
                    //
                    int newState = (oldState + WaiterCountIncrement) & ~WaiterWoken;
                    if (Interlocked.CompareExchange(ref _state, newState, oldState) == oldState)
                    {
                        break;
                    }
                }
            }

            //
            // Now we wait.
            //
            TimeoutTracker timeoutTracker = TimeoutTracker.Start(millisecondsTimeout);
            AutoResetEvent ev             = Event;

            while (true)
            {
                Contract.Assert(_state >= WaiterCountIncrement);

                bool waitSucceeded = ev.WaitOne(timeoutTracker.Remaining);

                while (true)
                {
                    int oldState = _state;
                    Contract.Assert(oldState >= WaiterCountIncrement);

                    // Clear the "waiter woken" bit.
                    int newState = oldState & ~WaiterWoken;

                    if ((oldState & Locked) == 0)
                    {
                        // The lock is available, try to get it.
                        newState |= Locked;
                        newState -= WaiterCountIncrement;

                        if (Interlocked.CompareExchange(ref _state, newState, oldState) == oldState)
                        {
                            goto GotTheLock;
                        }
                    }
                    else if (!waitSucceeded)
                    {
                        // The lock is not available, and we timed out.  We're not going to wait agin.
                        newState -= WaiterCountIncrement;

                        if (Interlocked.CompareExchange(ref _state, newState, oldState) == oldState)
                        {
                            return(false);
                        }
                    }
                    else
                    {
                        // The lock is not available, and we didn't time out.  We're going to wait again.
                        if (Interlocked.CompareExchange(ref _state, newState, oldState) == oldState)
                        {
                            break;
                        }
                    }
                }
            }

GotTheLock:
            Contract.Assert((_state | Locked) != 0);
            Contract.Assert(_owningThreadId == 0);
            Contract.Assert(_recursionCount == 0);
            _owningThreadId = currentThreadId;
            return(true);
        }
예제 #7
0
 /// <summary>
 /// Ensure the lock object is initialized.
 /// </summary>
 /// <param name="syncLock">A reference to a location containing a mutual exclusive lock. If <paramref name="syncLock"/> is null,
 /// a new object will be instantiated.</param>
 /// <returns>Initialized lock object.</returns>
 private static object EnsureLockInitialized(ref object syncLock) =>
 syncLock ??
 Interlocked.CompareExchange(ref syncLock, new object(), null) ??
 syncLock;
예제 #8
0
 public void Enter(ref bool lockTaken)
 {
     if (lockTaken)
     {
         lockTaken = false;
         throw new ArgumentException();
     }
     else
     {
         if (_disableThreadTracking)
         {
             var check = Interlocked.CompareExchange(ref _isHeld, 1, 0);
             if (check == 0)
             {
                 lockTaken = true;
             }
             else
             {
                 //Deadlock on recursion
                 TryEnter(-1, ref lockTaken);
             }
         }
         else
         {
             if (IsHeldByCurrentThread)
             {
                 //Throw on recursion
                 throw new LockRecursionException();
             }
             else
             {
                 if (Interlocked.CompareExchange(ref _isHeld, 1, 0) == 0 && ReferenceEquals(Interlocked.CompareExchange(ref _ownerThread, Thread.CurrentThread, null), null))
                 {
                     lockTaken = true;
                 }
                 else
                 {
                     TryEnter(-1, ref lockTaken);
                 }
             }
         }
     }
 }
예제 #9
0
 public void TryEnter(int millisecondsTimeout, ref bool lockTaken)
 {
     if (_disableThreadTracking)
     {
         if (ThreadingHelper.SpinWaitSet(ref _isHeld, 1, 0, millisecondsTimeout))
         {
             lockTaken = true;
         }
     }
     else
     {
         if (IsHeldByCurrentThread)
         {
             //Throw on recursion
             throw new LockRecursionException();
         }
         else
         {
             if (ThreadingHelper.SpinWaitSet(ref _isHeld, 1, 0, millisecondsTimeout) && ReferenceEquals(Interlocked.CompareExchange(ref _ownerThread, Thread.CurrentThread, null), null))
             {
                 lockTaken = true;
             }
         }
     }
 }
예제 #10
0
        void Cancellation(bool throwOnFirstException)
        {
            if (Interlocked.CompareExchange(ref state, StateCanceled, StateValid) != StateValid)
            {
                return;
            }

            handle.Set();

            if (linkedTokens != null)
            {
                UnregisterLinkedTokens();
            }

            var cbs = callbacks;

            if (cbs == null)
            {
                return;
            }

            List <Exception> exceptions = null;

            try {
                Action cb;
                for (int id = currId; id != int.MinValue; id--)
                {
                    if (!cbs.TryRemove(new CancellationTokenRegistration(id, this), out cb))
                    {
                        continue;
                    }
                    if (cb == null)
                    {
                        continue;
                    }

                    if (throwOnFirstException)
                    {
                        cb();
                    }
                    else
                    {
                        try {
                            cb();
                        } catch (Exception e) {
                            if (exceptions == null)
                            {
                                exceptions = new List <Exception> ();
                            }

                            exceptions.Add(e);
                        }
                    }
                }
            } finally {
                cbs.Clear();
            }

            if (exceptions != null)
            {
                throw new AggregateException(exceptions);
            }
        }