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 } }
public static UIntPtr VolatileRead(ref UIntPtr address) => Volatile.Read(ref address);
public static ulong VolatileRead(ref ulong address) => Volatile.Read(ref address);
public static uint VolatileRead(ref uint address) => Volatile.Read(ref address);
/// <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);
public static unsafe object LoadReferenceTypeField(IntPtr address) { return(Volatile.Read <Object>(ref Unsafe.As <IntPtr, object>(ref *(IntPtr *)address))); }
/// <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);
public static double VolatileRead(ref double address) => Volatile.Read(ref address);
public void GetMaxThreads(out int workerThreads, out int ioCompletionThreads) { workerThreads = Volatile.Read(ref _maxThreads); ioCompletionThreads = _legacy_maxIOCompletionThreads; }
/// <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);
/// <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);
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(); } }
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(); } }
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);
public static object VolatileRead(ref object address) => Volatile.Read(ref address);
/// <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); }
public static sbyte VolatileRead(ref sbyte address) => Volatile.Read(ref address);
public static float VolatileRead(ref float address) => Volatile.Read(ref address);
public static ushort VolatileRead(ref ushort address) => Volatile.Read(ref address);
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)); } }
/// <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);