Exemple #1
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
            }
        }
Exemple #2
0
 public static UIntPtr VolatileRead(ref UIntPtr address) => Volatile.Read(ref address);
Exemple #3
0
 public static ulong VolatileRead(ref ulong address) => Volatile.Read(ref address);
Exemple #4
0
 public static uint VolatileRead(ref uint address) => Volatile.Read(ref address);
Exemple #5
0
 /// <summary>
 /// Initializes a target reference type using the specified function if it has not already been
 /// initialized.
 /// </summary>
 /// <typeparam name="T">The reference type of the reference to be initialized.</typeparam>
 /// <param name="target">The reference of type <typeparamref name="T"/> to initialize if it has not
 /// already been initialized.</param>
 /// <param name="valueFactory">The <see cref="T:System.Func{T}"/> invoked to initialize the
 /// reference.</param>
 /// <returns>The initialized reference of type <typeparamref name="T"/>.</returns>
 /// <exception cref="T:System.MissingMemberException">Type <typeparamref name="T"/> does not have a
 /// default constructor.</exception>
 /// <exception cref="T:System.InvalidOperationException"><paramref name="valueFactory"/> returned
 /// null.</exception>
 /// <remarks>
 /// <para>
 /// This method may only be used on reference types, and <paramref name="valueFactory"/> may
 /// not return a null reference (Nothing in Visual Basic). To ensure initialization of value types or
 /// to allow null reference types, see other overloads of EnsureInitialized.
 /// </para>
 /// <para>
 /// This method may be used concurrently by multiple threads to initialize <paramref name="target"/>.
 /// In the event that multiple threads access this method concurrently, multiple instances of <typeparamref name="T"/>
 /// may be created, but only one will be stored into <paramref name="target"/>. In such an occurrence, this method will not dispose of the
 /// objects that were not stored.  If such objects must be disposed, it is up to the caller to determine
 /// if an object was not used and to then dispose of the object appropriately.
 /// </para>
 /// </remarks>
 public static T EnsureInitialized <T>(ref T target, Func <T> valueFactory) where T : class =>
 Volatile.Read(ref target) ?? EnsureInitializedCore <T>(ref target, valueFactory);
Exemple #6
0
 public static unsafe object LoadReferenceTypeField(IntPtr address)
 {
     return(Volatile.Read <Object>(ref Unsafe.As <IntPtr, object>(ref *(IntPtr *)address)));
 }
Exemple #7
0
        /// <summary>
        /// Signals that a participant has reached the barrier and waits for all other participants to reach
        /// the barrier as well, using a
        /// 32-bit signed integer to measure the time interval, while observing a <see cref="T:System.Threading.CancellationToken"/>.
        /// </summary>
        /// <param name="millisecondsTimeout">The number of milliseconds to wait, or <see cref="Timeout.Infinite"/>(-1) to wait indefinitely.</param>
        /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken"/> to
        /// observe.</param>
        /// <returns>true if all other participants reached the barrier; otherwise, false.</returns>
        /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="millisecondsTimeout"/> is a
        /// negative number other than -1, which represents an infinite time-out.</exception>
        /// <exception cref="T:System.InvalidOperationException">
        /// The method was invoked from within a post-phase action, the barrier currently has 0 participants,
        /// or the barrier is being used by more threads than are registered as participants.
        /// </exception>
        /// <exception cref="T:System.OperationCanceledException"><paramref name="cancellationToken"/> has been
        /// canceled.</exception>
        /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
        /// disposed.</exception>
        public bool SignalAndWait(int millisecondsTimeout, CancellationToken cancellationToken)
        {
            ThrowIfDisposed();
            cancellationToken.ThrowIfCancellationRequested();

            if (millisecondsTimeout < -1)
            {
                throw new ArgumentOutOfRangeException("millisecondsTimeout", millisecondsTimeout,
                                                      "The specified timeout must represent a value between -1 and Int32.MaxValue, inclusive.");
            }

            // in case of this is called from the PHA
            if (_actionCallerId != 0 && Thread.CurrentThread.ManagedThreadId == _actionCallerId)
            {
                throw new InvalidOperationException("This method may not be called from within the postPhaseAction.");
            }

            // local variables to extract the basic barrier variable and update them
            // The are declared here instead of inside the loop body because the will be used outside the loop
            bool sense; // The sense of the barrier *before* the phase associated with this SignalAndWait call completes
            int  total;
            int  current;
            int  currentTotal;
            long phase;
            var  spinner = new SpinWait();

            while (true)
            {
                currentTotal = Volatile.Read(ref _currentTotalCount);
                GetCurrentTotal(currentTotal, out current, out total, out sense);
                phase = CurrentPhaseNumber;
                // throw if zero participants
                if (total == 0)
                {
                    throw new InvalidOperationException("The barrier has no registered participants.");
                }
                // Try to detect if the number of threads for this phase exceeded the total number of participants or not
                // This can be detected if the current is zero which means all participants for that phase has arrived and the phase number is not changed yet
                if (current == 0 && sense != (CurrentPhaseNumber % 2 == 0))
                {
                    throw new InvalidOperationException("The number of threads using the barrier exceeded the total number of registered participants.");
                }
                //This is the last thread, finish the phase
                if (current + 1 == total)
                {
                    if (SetCurrentTotal(currentTotal, 0, total, !sense))
                    {
                        FinishPhase(sense);
                        return(true);
                    }
                }
                else if (SetCurrentTotal(currentTotal, current + 1, total, sense))
                {
                    break;
                }

                spinner.SpinOnce();
            }

            // ** Perform the real wait **
            // select the correct event to wait on, based on the current sense.
            var eventToWaitOn = (sense) ? _evenEvent : _oddEvent;

            var waitWasCanceled = false;
            var waitResult      = false;

            try
            {
                waitResult = DiscontinuousWait(eventToWaitOn, millisecondsTimeout, cancellationToken, phase);
            }
            catch (OperationCanceledException)
            {
                waitWasCanceled = true;
            }
            catch (ObjectDisposedException)// in case a race happen where one of the thread returned from SignalAndWait and the current thread calls Wait on a disposed event
            {
                // make sure the current phase for this thread is already finished, otherwise propagate the exception
                if (phase < CurrentPhaseNumber)
                {
                    waitResult = true;
                }
                else
                {
                    throw;
                }
            }

            if (!waitResult)
            {
                //reset the spinLock to prepare it for the next loop
                spinner.Reset();

                //If the wait timeout expired and all other thread didn't reach the barrier yet, update the current count back
                while (true)
                {
                    bool newSense;
                    currentTotal = Volatile.Read(ref _currentTotalCount);
                    GetCurrentTotal(currentTotal, out current, out total, out newSense);
                    // If the timeout expired and the phase has just finished, return true and this is considered as succeeded SignalAndWait
                    //otherwise the timeout expired and the current phase has not been finished yet, return false
                    //The phase is finished if the phase member variable is changed (incremented) or the sense has been changed
                    // we have to use the statements in the comparison below for two cases:
                    // 1- The sense is changed but the last thread didn't update the phase yet
                    // 2- The phase is already incremented but the sense flipped twice due to the termination of the next phase
                    if (phase < CurrentPhaseNumber || sense != newSense)
                    {
                        // The current phase has been finished, but we shouldn't return before the events are set/reset otherwise this thread could start
                        // next phase and the appropriate event has not reset yet which could make it return immediately from the next phase SignalAndWait
                        // before waiting other threads
                        WaitCurrentPhase(eventToWaitOn, phase);
                        Debug.Assert(phase < CurrentPhaseNumber);
                        break;
                    }
                    //The phase has not been finished yet, try to update the current count.
                    if (SetCurrentTotal(currentTotal, current - 1, total, sense))
                    {
                        //if here, then the attempt to back out was successful.
                        //throw (a fresh) OCE if cancellation woke the wait
                        //or return false if it was the timeout that woke the wait.
                        //
                        if (waitWasCanceled)
                        {
                            throw new NewOperationCanceledException("The operation was canceled.", cancellationToken);
                        }
                        return(false);
                    }
                    spinner.SpinOnce();
                }
            }

            if (_exception != null)
            {
                throw new BarrierPostPhaseException(_exception);
            }

            return(true);
        }
 public int GetMaxThreads() => Volatile.Read(ref _maxThreads);
Exemple #9
0
 public static double VolatileRead(ref double address) => Volatile.Read(ref address);
Exemple #10
0
 public void GetMaxThreads(out int workerThreads, out int ioCompletionThreads)
 {
     workerThreads       = Volatile.Read(ref _maxThreads);
     ioCompletionThreads = _legacy_maxIOCompletionThreads;
 }
Exemple #11
0
 /// <summary>
 /// Initializes a target reference type with the type's default constructor if the target has not
 /// already been initialized.
 /// </summary>
 /// <typeparam name="T">The reference type of the reference to be initialized.</typeparam>
 /// <param name="target">A reference of type <typeparamref name="T"/> to initialize if it has not
 /// already been initialized.</param>
 /// <returns>The initialized reference of type <typeparamref name="T"/>.</returns>
 /// <exception cref="T:System.MissingMemberException">Type <typeparamref name="T"/> does not have a default
 /// constructor.</exception>
 /// <exception cref="T:System.MemberAccessException">
 /// Permissions to access the constructor of type <typeparamref name="T"/> were missing.
 /// </exception>
 /// <remarks>
 /// <para>
 /// This method may only be used on reference types. To ensure initialization of value
 /// types, see other overloads of EnsureInitialized.
 /// </para>
 /// <para>
 /// This method may be used concurrently by multiple threads to initialize <paramref name="target"/>.
 /// In the event that multiple threads access this method concurrently, multiple instances of <typeparamref name="T"/>
 /// may be created, but only one will be stored into <paramref name="target"/>. In such an occurrence, this method will not dispose of the
 /// objects that were not stored.  If such objects must be disposed, it is up to the caller to determine
 /// if an object was not used and to then dispose of the object appropriately.
 /// </para>
 /// </remarks>
 public static T EnsureInitialized <T>(ref T target) where T : class =>
 Volatile.Read(ref target) ?? EnsureInitializedCore(ref target);
Exemple #12
0
 /// <summary>
 /// Initializes a target reference type with a specified function if it has not already been initialized.
 /// </summary>
 /// <typeparam name="T">The type of the reference to be initialized. Has to be reference type.</typeparam>
 /// <param name="target">A reference of type <typeparamref name="T"/> to initialize if it has not already been initialized.</param>
 /// <param name="syncLock">A reference to an object used as the mutually exclusive lock for initializing
 /// <paramref name="target"/>. If <paramref name="syncLock"/> is null, a new object will be instantiated.</param>
 /// <param name="valueFactory">The <see cref="T:System.Func{T}"/> invoked to initialize the reference.</param>
 /// <returns>The initialized value of type <typeparamref name="T"/>.</returns>
 public static T EnsureInitialized <T>(ref T target, ref object syncLock, Func <T> valueFactory) where T : class =>
 Volatile.Read(ref target) ?? EnsureInitializedCore(ref target, ref syncLock, valueFactory);
Exemple #13
0
        private ManualResetEvent GetOrCreateWaitHandle()
        {
            // At the end of this method: _status will be (int)Status.HandleCreated or ObjectDisposedException is thrown
            var spinWait = new SpinWait();

            while (true)
            {
                var status = (Status)Volatile.Read(ref _status);
                switch (status)
                {
                case Status.Disposed:
                    // Disposed
                    throw new ObjectDisposedException(nameof(ManualResetEventSlim));

                case Status.NotSet:
                    // Indicate we will be creating the handle
                    status = (Status)Interlocked.CompareExchange(ref _status, (int)Status.HandleRequestedNotSet, (int)status);
                    if (status == Status.NotSet)
                    {
                        // Create the handle
                        var created = new ManualResetEvent(false);
                        // Set the handle
                        Volatile.Write(ref _handle, created);
                        // Notify that the handle is ready
                        Volatile.Write(ref _status, (int)Status.HandleReadyNotSet);
                        // Return the handle we created
                        return(created);
                    }

                    // Must has been disposed, or another thread is creating the handle
                    break;

                case Status.Set:
                    // Indicate we will be creating the handle
                    status = (Status)Interlocked.CompareExchange(ref _status, (int)Status.HandleRequestedSet, (int)status);
                    if (status == Status.Set)
                    {
                        // Create the handle
                        var created = new ManualResetEvent(true);
                        // Set the handle
                        Volatile.Write(ref _handle, created);
                        // Notify that the handle is ready
                        Volatile.Write(ref _status, (int)Status.HandleReadySet);
                        // Return the handle we created
                        return(created);
                    }

                    // Must has been disposed, or another thread is creating the handle
                    break;

                case Status.HandleRequestedNotSet:
                case Status.HandleRequestedSet:
                    // Another thread is creating the wait handle
                    // SpinWait
                    break;

                case Status.HandleReadyNotSet:
                case Status.HandleReadySet:
                    // The handle already exists
                    // Get the handle that is already created
                    var handle = Volatile.Read(ref _handle);
                    if (handle != null)
                    {
                        // Return it
                        return(handle);
                    }

                    // Probably Disposed
                    break;

                default:
                    // Should not happen
                    break;
                }

                spinWait.SpinOnce();
            }
        }
Exemple #14
0
        public void Set()
        {
            var spinWait = new SpinWait();

            while (true)
            {
                var status = (Status)Volatile.Read(ref _status);
                switch (status)
                {
                case Status.Disposed:
                    // Disposed
                    // Fail saliently
                    return;

                case Status.NotSet:
                    // Set if Reset
                    status = (Status)Interlocked.CompareExchange(ref _status, (int)Status.Set, (int)Status.NotSet);
                    if (status == Status.NotSet || status == Status.Set)
                    {
                        // We Set it or it was already Set
                        // Either way, we are done
                        return;
                    }

                    // Must has been disposed, or the wait handle requested
                    break;

                case Status.HandleRequestedNotSet:
                    // Another thread is creating the wait handle
                    // SpinWait
                    break;

                case Status.HandleReadyNotSet:
                    // Set if Reset
                    status = (Status)Interlocked.CompareExchange(ref _status, (int)Status.HandleReadySet, (int)Status.HandleReadyNotSet);
                    switch (status)
                    {
                    case Status.HandleReadyNotSet:
                    {
                        // We set it
                        // Update the wait handle
                        var handle = Volatile.Read(ref _handle);
                        if (handle != null)
                        {
                            // Reset it
                            handle.Set();
                            // Done
                            return;
                        }

                        break;
                    }

                    case Status.HandleReadySet:
                        // Another thread set it
                        // we are done
                        return;

                    default:
                        break;
                    }

                    // Probably Disposed
                    break;

                case Status.Set:
                case Status.HandleRequestedSet:
                case Status.HandleReadySet:
                    // Nothing to do
                    return;

                default:
                    // Should not happen
                    break;
                }

                spinWait.SpinOnce();
            }
        }
Exemple #15
0
            public bool LocalPop(out IThreadPoolWorkItem obj)
            {
                while (true)
                {
                    // Decrement the tail using a fence to ensure subsequent read doesn't come before.
                    int tail = m_tailIndex;
                    if (m_headIndex >= tail)
                    {
                        obj = null;
                        return(false);
                    }

                    tail -= 1;
                    Interlocked.Exchange(ref m_tailIndex, tail);

                    // If there is no interaction with a take, we can head down the fast path.
                    if (m_headIndex <= tail)
                    {
                        int idx = tail & m_mask;
                        obj = Volatile.Read(ref m_array[idx]);

                        // Check for nulls in the array.
                        if (obj == null)
                        {
                            continue;
                        }

                        m_array[idx] = null;
                        return(true);
                    }
                    else
                    {
                        // Interaction with takes: 0 or 1 elements left.
                        bool lockTaken = false;
                        try
                        {
                            m_foreignLock.Enter(ref lockTaken);

                            if (m_headIndex <= tail)
                            {
                                // Element still available. Take it.
                                int idx = tail & m_mask;
                                obj = Volatile.Read(ref m_array[idx]);

                                // Check for nulls in the array.
                                if (obj == null)
                                {
                                    continue;
                                }

                                m_array[idx] = null;
                                return(true);
                            }
                            else
                            {
                                // We lost the race, element was stolen, restore the tail.
                                m_tailIndex = tail + 1;
                                obj         = null;
                                return(false);
                            }
                        }
                        finally
                        {
                            if (lockTaken)
                            {
                                m_foreignLock.Exit(false);
                            }
                        }
                    }
                }
            }
 public int GetMinThreads() => Volatile.Read(ref _minThreads);
Exemple #17
0
 public static object VolatileRead(ref object address) => Volatile.Read(ref address);
Exemple #18
0
        /// <summary>
        /// Notifies the <see cref="Barrier"/> that there will be additional participants.
        /// </summary>
        /// <param name="participantCount">The number of additional participants to add to the
        /// barrier.</param>
        /// <returns>The phase number of the barrier in which the new participants will first
        /// participate.</returns>
        /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="participantCount"/> is less than
        /// 0.</exception>
        /// <exception cref="T:System.ArgumentOutOfRangeException">Adding <paramref name="participantCount"/> participants would cause the
        /// barrier's participant count to exceed <see cref="T:System.Int16.MaxValue"/>.</exception>
        /// <exception cref="T:System.InvalidOperationException">
        /// The method was invoked from within a post-phase action.
        /// </exception>
        /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
        /// disposed.</exception>
        public long AddParticipants(int participantCount)
        {
            // check dispose
            ThrowIfDisposed();

            if (participantCount < 1)
            {
                throw new ArgumentOutOfRangeException("participantCount", participantCount,
                                                      "The participantCount argument must be a positive value.");
            }
            if (participantCount > _maxParticipants) //overflow
            {
                throw new ArgumentOutOfRangeException("participantCount",
                                                      "Adding participantCount participants would result in the number of participants exceeding the maximum number allowed.");
            }

            // in case of this is called from the PHA
            if (_actionCallerId != 0 && Thread.CurrentThread.ManagedThreadId == _actionCallerId)
            {
                throw new InvalidOperationException("This method may not be called from within the postPhaseAction.");
            }

            var  spinner = new SpinWait();
            long newPhase;

            while (true)
            {
                var  currentTotal = Volatile.Read(ref _currentTotalCount);
                int  total;
                int  current;
                bool sense;
                GetCurrentTotal(currentTotal, out current, out total, out sense);
                if (participantCount + total > _maxParticipants) //overflow
                {
                    throw new ArgumentOutOfRangeException("participantCount",
                                                          "Adding participantCount participants would result in the number of participants exceeding the maximum number allowed.");
                }

                if (SetCurrentTotal(currentTotal, current, total + participantCount, sense))
                {
                    // Calculating the first phase for that participant, if the current phase already finished return the next phase else return the current phase
                    // To know that the current phase is  the sense doesn't match the
                    // phase odd even, so that means it didn't yet change the phase count, so currentPhase +1 is returned, otherwise currentPhase is returned
                    var currPhase = CurrentPhaseNumber;
                    newPhase = (sense != (currPhase % 2 == 0)) ? currPhase + 1 : currPhase;

                    // If this participant is going to join the next phase, which means the postPhaseAction is being running, this participants must wait until this done
                    // and its event is reset.
                    // Without that, if the postPhaseAction takes long time, this means the event that the current participant is going to wait on is still set
                    // (FinishPhase didn't reset it yet) so it should wait until it reset
                    if (newPhase != currPhase)
                    {
                        // Wait on the opposite event
                        if (sense)
                        {
                            _oddEvent.Wait();
                        }
                        else
                        {
                            _evenEvent.Wait();
                        }
                    }

                    //This else to fix the racing where the current phase has been finished, m_currentPhase has been updated but the events have not been set/reset yet
                    // otherwise when this participant calls SignalAndWait it will wait on a set event however all other participants have not arrived yet.
                    else
                    {
                        if (sense && _evenEvent.IsSet)
                        {
                            _evenEvent.Reset();
                        }
                        else if (!sense && _oddEvent.IsSet)
                        {
                            _oddEvent.Reset();
                        }
                    }
                    break;
                }
                spinner.SpinOnce();
            }
            return(newPhase);
        }
Exemple #19
0
 public static sbyte VolatileRead(ref sbyte address) => Volatile.Read(ref address);
Exemple #20
0
 public static float VolatileRead(ref float address) => Volatile.Read(ref address);
Exemple #21
0
 public static ushort VolatileRead(ref ushort address) => Volatile.Read(ref address);
Exemple #22
0
        public void Log(string txt, LogType type         = LogType.Log, bool showLogStack = true, Exception e = null,
                        Dictionary <string, string> data = null)
        {
            var dataString = string.Empty;

            if (data != null)
            {
                dataString = DataToString.DetailString(data);
            }

            var frame = $"[{DateTime.UtcNow.ToString("HH:mm:ss.fff")}] thread: {Environment.CurrentManagedThreadId}";

            try
            {
                if (MAINTHREADID == Environment.CurrentManagedThreadId)
                {
                    frame += $" frame: {Time.frameCount}";
                }
            }
            catch
            {
                //there is something wrong with  Environment.CurrentManagedThreadId
            }

            StackTrace stack = null;

#if UNITY_EDITOR
            stack = new StackTrace(3, true);
#else
            if (type == LogType.Error || type == LogType.Exception)
            {
                stack = new StackTrace(3, true);
            }
#endif

            if (Volatile.Read(ref Console.batchLog) == true)
            {
                var stackString = stack == null ? string.Empty : stack.GetFrame(0).ToString();
                var strArray    = Encoding.UTF8.GetBytes(txt.FastConcat(stackString));
                var logHash     = Murmur3.MurmurHash3_x86_32(strArray, SEED);

                if (_batchedErrorLogs.ContainsKey(logHash))
                {
                    _batchedErrorLogs[logHash] = new ErrorLogObject(_batchedErrorLogs[logHash]);
                }
                else
                {
#if !UNITY_EDITOR
                    if (type == LogType.Error)
                    {
                        stack = new StackTrace(3, true);
                    }
#endif

                    _batchedErrorLogs[logHash] =
                        new ErrorLogObject(txt, stack, type, e, frame, showLogStack, dataString);
                }
            }
            else
            {
#if !UNITY_EDITOR
                if (type == LogType.Error)
                {
                    stack = new StackTrace(3, true);
                }
#endif

                _notBatchedQueue.Enqueue(new ErrorLogObject(txt, stack, type, e, frame, showLogStack, dataString,
                                                            0));
            }
        }
Exemple #23
0
 /// <summary>
 /// Initializes a target reference type with the type's default constructor if the target has not
 /// already been initialized.
 /// </summary>
 /// <typeparam name="T">The refence type of the reference to be initialized.</typeparam>
 /// <param name="target">A reference of type <typeparamref name="T"/> to initialize if it has not
 /// already been initialized.</param>
 /// <returns>The initialized reference of type <typeparamref name="T"/>.</returns>
 /// <exception cref="T:System.MissingMemberException">Type <typeparamref name="T"/> does not have a default
 /// constructor.</exception>
 /// <exception cref="T:System.MemberAccessException">
 /// Permissions to access the constructor of type <typeparamref name="T"/> were missing.
 /// </exception>
 /// <remarks>
 /// <para>
 /// This method may only be used on reference types. To ensure initialization of value
 /// types, see other overloads of EnsureInitialized.
 /// </para>
 /// <para>
 /// This method may be used concurrently by multiple threads to initialize <paramref name="target"/>.
 /// In the event that multiple threads access this method concurrently, multiple instances of <typeparamref name="T"/>
 /// may be created, but only one will be stored into <paramref name="target"/>. In such an occurrence, this method will not dispose of the
 /// objects that were not stored.  If such objects must be disposed, it is up to the caller to determine
 /// if an object was not used and to then dispose of the object appropriately.
 /// </para>
 /// </remarks>
 public static T EnsureInitialized <T>(ref T target) where T : class =>
 Volatile.Read <T>(ref target) ?? EnsureInitializedCore <T>(ref target, LazyHelpers <T> .ActivatorFactorySelectorFunc);