<Compile Include="$(BclSourcesRoot)\System\Threading\ClrThreadPoolBoundHandle.cs" />
<Compile Include="$(BclSourcesRoot)\System\Threading\ClrThreadPoolBoundHandleOverlapped.cs" />
<Compile Include="$(BclSourcesRoot)\System\Threading\ClrThreadPoolPreAllocatedOverlapped.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Threading\Interlocked.cs" />
+ <Compile Include="$(BclSourcesRoot)\System\Threading\Interlocked.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Threading\Monitor.cs" />
<Compile Include="$(BclSourcesRoot)\System\Threading\Overlapped.cs" />
<Compile Include="$(BclSourcesRoot)\System\Threading\StackCrawlMark.cs" />
-
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28902.138
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
+ ..\..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{3da06c3a-2e7b-4cb7-80ed-9b12916013f9}*SharedItemsImports = 5
..\..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{845c8b26-350b-4e63-bd11-2c8150444e28}*SharedItemsImports = 13
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Internal.Runtime.CompilerServices;
+
+namespace System.Threading
+{
+ public static partial class Interlocked
+ {
+ #region Increment
+ /// <summary>Increments a specified variable and stores the result, as an atomic operation.</summary>
+ /// <param name="location">The variable whose value is to be incremented.</param>
+ /// <returns>The incremented value.</returns>
+ /// <exception cref="NullReferenceException">The address of location is a null pointer.</exception>
+ public static int Increment(ref int location) =>
+ Add(ref location, 1);
+
+ /// <summary>Increments a specified variable and stores the result, as an atomic operation.</summary>
+ /// <param name="location">The variable whose value is to be incremented.</param>
+ /// <returns>The incremented value.</returns>
+ /// <exception cref="NullReferenceException">The address of location is a null pointer.</exception>
+ public static long Increment(ref long location) =>
+ Add(ref location, 1);
+ #endregion
+
+ #region Decrement
+ /// <summary>Decrements a specified variable and stores the result, as an atomic operation.</summary>
+ /// <param name="location">The variable whose value is to be decremented.</param>
+ /// <returns>The decremented value.</returns>
+ /// <exception cref="NullReferenceException">The address of location is a null pointer.</exception>
+ public static int Decrement(ref int location) =>
+ Add(ref location, -1);
+
+ /// <summary>Decrements a specified variable and stores the result, as an atomic operation.</summary>
+ /// <param name="location">The variable whose value is to be decremented.</param>
+ /// <returns>The decremented value.</returns>
+ /// <exception cref="NullReferenceException">The address of location is a null pointer.</exception>
+ public static long Decrement(ref long location) =>
+ Add(ref location, -1);
+ #endregion
+
+ #region Exchange
+ /// <summary>Sets a 32-bit signed integer to a specified value and returns the original value, as an atomic operation.</summary>
+ /// <param name="location1">The variable to set to the specified value.</param>
+ /// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
+ /// <returns>The original value of <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
+ [Intrinsic]
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ public static extern int Exchange(ref int location1, int value);
+
+ /// <summary>Sets a 64-bit signed integer to a specified value and returns the original value, as an atomic operation.</summary>
+ /// <param name="location1">The variable to set to the specified value.</param>
+ /// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
+ /// <returns>The original value of <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ public static extern long Exchange(ref long location1, long value);
+
+ /// <summary>Sets a single-precision floating point number to a specified value and returns the original value, as an atomic operation.</summary>
+ /// <param name="location1">The variable to set to the specified value.</param>
+ /// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
+ /// <returns>The original value of <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ public static extern float Exchange(ref float location1, float value);
+
+ /// <summary>Sets a double-precision floating point number to a specified value and returns the original value, as an atomic operation.</summary>
+ /// <param name="location1">The variable to set to the specified value.</param>
+ /// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
+ /// <returns>The original value of <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ public static extern double Exchange(ref double location1, double value);
+
+ /// <summary>Sets an object to the specified value and returns a reference to the original object, as an atomic operation.</summary>
+ /// <param name="location1">The variable to set to the specified value.</param>
+ /// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
+ /// <returns>The original value of <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ [return: NotNullIfNotNull("location1")]
+ public static extern object? Exchange([NotNullIfNotNull("value")] ref object? location1, object? value);
+
+ /// <summary>Sets a platform-specific handle or pointer to a specified value and returns the original value, as an atomic operation.</summary>
+ /// <param name="location1">The variable to set to the specified value.</param>
+ /// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
+ /// <returns>The original value of <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ public static extern IntPtr Exchange(ref IntPtr location1, IntPtr value);
+
+ // The below whole method reduces to a single call to Exchange(ref object, object) but
+ // the JIT thinks that it will generate more native code than it actually does.
+
+ /// <summary>Sets a variable of the specified type <typeparamref name="T"/> to a specified value and returns the original value, as an atomic operation.</summary>
+ /// <param name="location1">The variable to set to the specified value.</param>
+ /// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
+ /// <returns>The original value of <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
+ /// <typeparam name="T">The type to be used for <paramref name="location1"/> and <paramref name="value"/>. This type must be a reference type.</typeparam>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [return: NotNullIfNotNull("location1")]
+ public static T Exchange<T>([NotNullIfNotNull("value")] ref T location1, T value) where T : class? =>
+ Unsafe.As<T>(Exchange(ref Unsafe.As<T, object?>(ref location1), value));
+ #endregion
+
+ #region CompareExchange
+ /// <summary>Compares two 32-bit signed integers for equality and, if they are equal, replaces the first value.</summary>
+ /// <param name="location1">The destination, whose value is compared with <paramref name="comparand"/> and possibly replaced.</param>
+ /// <param name="value">The value that replaces the destination value if the comparison results in equality.</param>
+ /// <param name="comparand">The value that is compared to the value at <paramref name="location1"/>.</param>
+ /// <returns>The original value in <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ [Intrinsic]
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ public static extern int CompareExchange(ref int location1, int value, int comparand);
+
+ /// <summary>Compares two 64-bit signed integers for equality and, if they are equal, replaces the first value.</summary>
+ /// <param name="location1">The destination, whose value is compared with <paramref name="comparand"/> and possibly replaced.</param>
+ /// <param name="value">The value that replaces the destination value if the comparison results in equality.</param>
+ /// <param name="comparand">The value that is compared to the value at <paramref name="location1"/>.</param>
+ /// <returns>The original value in <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ public static extern long CompareExchange(ref long location1, long value, long comparand);
+
+ /// <summary>Compares two single-precision floating point numbers for equality and, if they are equal, replaces the first value.</summary>
+ /// <param name="location1">The destination, whose value is compared with <paramref name="comparand"/> and possibly replaced.</param>
+ /// <param name="value">The value that replaces the destination value if the comparison results in equality.</param>
+ /// <param name="comparand">The value that is compared to the value at <paramref name="location1"/>.</param>
+ /// <returns>The original value in <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ public static extern float CompareExchange(ref float location1, float value, float comparand);
+
+ /// <summary>Compares two double-precision floating point numbers for equality and, if they are equal, replaces the first value.</summary>
+ /// <param name="location1">The destination, whose value is compared with <paramref name="comparand"/> and possibly replaced.</param>
+ /// <param name="value">The value that replaces the destination value if the comparison results in equality.</param>
+ /// <param name="comparand">The value that is compared to the value at <paramref name="location1"/>.</param>
+ /// <returns>The original value in <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ public static extern double CompareExchange(ref double location1, double value, double comparand);
+
+ /// <summary>Compares two objects for reference equality and, if they are equal, replaces the first object.</summary>
+ /// <param name="location1">The destination object that is compared by reference with <paramref name="comparand"/> and possibly replaced.</param>
+ /// <param name="value">The object that replaces the destination object if the reference comparison results in equality.</param>
+ /// <param name="comparand">The object that is compared by reference to the object at <paramref name="location1"/>.</param>
+ /// <returns>The original value in <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ [return: NotNullIfNotNull("location1")]
+ public static extern object? CompareExchange(ref object? location1, object? value, object? comparand);
+
+ /// <summary>Compares two platform-specific handles or pointers for equality and, if they are equal, replaces the first one.</summary>
+ /// <param name="location1">The destination <see cref="IntPtr"/>, whose value is compared with the value of <paramref name="comparand"/> and possibly replaced by <paramref name="value"/>.</param>
+ /// <param name="value">The <see cref="IntPtr"/> that replaces the destination value if the comparison results in equality.</param>
+ /// <param name="comparand">The <see cref="IntPtr"/> that is compared to the value at <paramref name="location1"/>.</param>
+ /// <returns>The original value in <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ public static extern IntPtr CompareExchange(ref IntPtr location1, IntPtr value, IntPtr comparand);
+
+ // Note that getILIntrinsicImplementationForInterlocked() in vm\jitinterface.cpp replaces
+ // the body of the following method with the the following IL:
+ // ldarg.0
+ // ldarg.1
+ // ldarg.2
+ // call System.Threading.Interlocked::CompareExchange(ref Object, Object, Object)
+ // ret
+ // The workaround is no longer strictly necessary now that we have Unsafe.As but it does
+ // have the advantage of being less sensitive to JIT's inliner decisions.
+
+ /// <summary>Compares two instances of the specified reference type <typeparamref name="T"/> for reference equality and, if they are equal, replaces the first one.</summary>
+ /// <param name="location1">The destination, whose value is compared by reference with <paramref name="comparand"/> and possibly replaced.</param>
+ /// <param name="value">The value that replaces the destination value if the comparison by reference results in equality.</param>
+ /// <param name="comparand">The object that is compared by reference to the value at <paramref name="location1"/>.</param>
+ /// <returns>The original value in <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ /// <typeparam name="T">The type to be used for <paramref name="location1"/>, <paramref name="value"/>, and <paramref name="comparand"/>. This type must be a reference type.</typeparam>
+ [return: NotNullIfNotNull("location1")]
+ [Intrinsic]
+ public static T CompareExchange<T>(ref T location1, T value, T comparand) where T : class? =>
+ Unsafe.As<T>(CompareExchange(ref Unsafe.As<T, object?>(ref location1), value, comparand));
+ #endregion
+
+ #region Add
+ /// <summary>Adds two 32-bit signed integers and replaces the first integer with the sum, as an atomic operation.</summary>
+ /// <param name="location1">A variable containing the first value to be added. The sum of the two values is stored in <paramref name="location1"/>.</param>
+ /// <param name="value">The value to be added to the integer at <paramref name="location1"/>.</param>
+ /// <returns>The new value stored at <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ public static int Add(ref int location1, int value) =>
+ ExchangeAdd(ref location1, value) + value;
+
+ /// <summary>Adds two 64-bit signed integers and replaces the first integer with the sum, as an atomic operation.</summary>
+ /// <param name="location1">A variable containing the first value to be added. The sum of the two values is stored in <paramref name="location1"/>.</param>
+ /// <param name="value">The value to be added to the integer at <paramref name="location1"/>.</param>
+ /// <returns>The new value stored at <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ public static long Add(ref long location1, long value) =>
+ ExchangeAdd(ref location1, value) + value;
+
+ [Intrinsic]
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern int ExchangeAdd(ref int location1, int value);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern long ExchangeAdd(ref long location1, long value);
+ #endregion
+
+ #region Read
+ /// <summary>Returns a 64-bit signed value, loaded as an atomic operation.</summary>
+ /// <param name="location">The 64-bit value to be loaded.</param>
+ /// <returns>The loaded value.</returns>
+ public static long Read(ref long location) =>
+ CompareExchange(ref location, 0, 0);
+ #endregion
+
+ #region MemoryBarrier
+ /// <summary>
+ /// Synchronizes memory access as follows:
+ /// The processor that executes the current thread cannot reorder instructions in such a way that memory accesses before
+ /// the call to <see cref="MemoryBarrier"/> execute after memory accesses that follow the call to <see cref="MemoryBarrier"/>.
+ /// </summary>
+ [Intrinsic]
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ public static extern void MemoryBarrier();
+
+ [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)]
+ private static extern void _MemoryBarrierProcessWide();
+
+ /// <summary>Provides a process-wide memory barrier that ensures that reads and writes from any CPU cannot move across the barrier.</summary>
+ public static void MemoryBarrierProcessWide() => _MemoryBarrierProcessWide();
+ #endregion
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Runtime.CompilerServices;
-using Internal.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Diagnostics.CodeAnalysis;
-
-namespace System.Threading
-{
- /// <summary>
- /// After much discussion, we decided the Interlocked class doesn't need
- /// any HPA's for synchronization or external threading. They hurt C#'s
- /// codegen for the yield keyword, and arguably they didn't protect much.
- /// Instead, they penalized people (and compilers) for writing threadsafe
- /// code.
- /// </summary>
- public static class Interlocked
- {
- /// <summary>
- /// Implemented: int, long
- /// </summary>
- public static int Increment(ref int location)
- {
- return Add(ref location, 1);
- }
-
- public static long Increment(ref long location)
- {
- return Add(ref location, 1);
- }
-
- /// <summary>
- /// Implemented: int, long
- /// </summary>
- public static int Decrement(ref int location)
- {
- return Add(ref location, -1);
- }
-
- public static long Decrement(ref long location)
- {
- return Add(ref location, -1);
- }
-
- /// <summary>
- /// Implemented: int, long, float, double, Object, IntPtr
- /// </summary>
- [Intrinsic]
- [MethodImpl(MethodImplOptions.InternalCall)]
- public static extern int Exchange(ref int location1, int value);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- public static extern long Exchange(ref long location1, long value);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- public static extern float Exchange(ref float location1, float value);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- public static extern double Exchange(ref double location1, double value);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- [return: NotNullIfNotNull("location1")]
- public static extern object? Exchange([NotNullIfNotNull("value")] ref object? location1, object? value);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- public static extern IntPtr Exchange(ref IntPtr location1, IntPtr value);
-
- // This whole method reduces to a single call to Exchange(ref object, object) but
- // the JIT thinks that it will generate more native code than it actually does.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- [return: NotNullIfNotNull("location1")]
- public static T Exchange<T>([NotNullIfNotNull("value")] ref T location1, T value) where T : class?
- {
- return Unsafe.As<T>(Exchange(ref Unsafe.As<T, object?>(ref location1), value));
- }
-
- /// <summary>
- /// Implemented: int, long, float, double, Object, IntPtr
- /// </summary>
- [Intrinsic]
- [MethodImpl(MethodImplOptions.InternalCall)]
- public static extern int CompareExchange(ref int location1, int value, int comparand);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- public static extern long CompareExchange(ref long location1, long value, long comparand);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- public static extern float CompareExchange(ref float location1, float value, float comparand);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- public static extern double CompareExchange(ref double location1, double value, double comparand);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- [return: NotNullIfNotNull("location1")]
- public static extern object? CompareExchange(ref object? location1, object? value, object? comparand);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- public static extern IntPtr CompareExchange(ref IntPtr location1, IntPtr value, IntPtr comparand);
-
- // Note that getILIntrinsicImplementationForInterlocked() in vm\jitinterface.cpp replaces
- // the body of this method with the the following IL:
- // ldarg.0
- // ldarg.1
- // ldarg.2
- // call System.Threading.Interlocked::CompareExchange(ref Object, Object, Object)
- // ret
- // The workaround is no longer strictly necessary now that we have Unsafe.As but it does
- // have the advantage of being less sensitive to JIT's inliner decisions.
- [return: NotNullIfNotNull("location1")]
- [Intrinsic]
- public static T CompareExchange<T>(ref T location1, T value, T comparand) where T : class?
- {
- return Unsafe.As<T>(CompareExchange(ref Unsafe.As<T, object?>(ref location1), value, comparand));
- }
-
- // BCL-internal overload that returns success via a ref bool param, useful for reliable spin locks.
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int CompareExchange(ref int location1, int value, int comparand, ref bool succeeded);
-
- /// <summary>
- /// Implemented: int, long
- /// </summary>
- [Intrinsic]
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int ExchangeAdd(ref int location1, int value);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern long ExchangeAdd(ref long location1, long value);
-
- public static int Add(ref int location1, int value)
- {
- return ExchangeAdd(ref location1, value) + value;
- }
-
- public static long Add(ref long location1, long value)
- {
- return ExchangeAdd(ref location1, value) + value;
- }
-
- public static long Read(ref long location)
- {
- return Interlocked.CompareExchange(ref location, 0, 0);
- }
-
- [Intrinsic]
- [MethodImpl(MethodImplOptions.InternalCall)]
- public static extern void MemoryBarrier();
-
- [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)]
- private static extern void _MemoryBarrierProcessWide();
-
- public static void MemoryBarrierProcessWide()
- {
- _MemoryBarrierProcessWide();
- }
- }
-}
}
FCIMPLEND
-FCIMPL4(INT32, COMInterlocked::CompareExchangeReliableResult, INT32* location, INT32 value, INT32 comparand, CLR_BOOL* succeeded)
-{
- FCALL_CONTRACT;
-
- if( NULL == location) {
- FCThrow(kNullReferenceException);
- }
-
- INT32 result = FastInterlockCompareExchange((LONG*)location, value, comparand);
- if (result == comparand)
- *succeeded = true;
-
- return result;
-}
-FCIMPLEND
-
FCIMPL3_IVV(INT64, COMInterlocked::CompareExchange64, INT64* location, INT64 value, INT64 comparand)
{
FCALL_CONTRACT;
static FCDECL2_IV(INT64, Exchange64, INT64 *location, INT64 value);
static FCDECL2(LPVOID, ExchangePointer, LPVOID* location, LPVOID value);
static FCDECL3(INT32, CompareExchange, INT32* location, INT32 value, INT32 comparand);
- static FCDECL4(INT32, CompareExchangeReliableResult, INT32* location, INT32 value, INT32 comparand, CLR_BOOL* succeeded);
static FCDECL3_IVV(INT64, CompareExchange64, INT64* location, INT64 value, INT64 comparand);
static FCDECL3(LPVOID, CompareExchangePointer, LPVOID* location, LPVOID value, LPVOID comparand);
static FCDECL2_IV(float, ExchangeFloat, float *location, float value);
FCFuncElementSig("CompareExchange", &gsig_SM_RefDbl_Dbl_Dbl_RetDbl, COMInterlocked::CompareExchangeDouble)
FCFuncElementSig("CompareExchange", &gsig_SM_RefFlt_Flt_Flt_RetFlt, COMInterlocked::CompareExchangeFloat)
FCFuncElementSig("CompareExchange", &gsig_SM_RefObj_Obj_Obj_RetObj, COMInterlocked::CompareExchangeObject)
- FCFuncElementSig("CompareExchange", &gsig_SM_RefInt_Int_Int_RefBool_RetInt, COMInterlocked::CompareExchangeReliableResult)
FCFuncElementSig("CompareExchange", &gsig_SM_RefIntPtr_IntPtr_IntPtr_RetIntPtr, COMInterlocked::CompareExchangePointer)
FCIntrinsicSig("ExchangeAdd", &gsig_SM_RefInt_Int_RetInt, COMInterlocked::ExchangeAdd32, CORINFO_INTRINSIC_InterlockedXAdd32)
FCIntrinsicSig("ExchangeAdd", &gsig_SM_RefLong_Long_RetLong, COMInterlocked::ExchangeAdd64, CORINFO_INTRINSIC_InterlockedXAdd64)
get => (Volatile.Read(ref _data) & bit) == bit;
set
{
- while (true)
+ if (value)
{
- int oldValue = _data;
- int newValue = value ? oldValue | bit : oldValue &= ~bit;
- if (Interlocked.CompareExchange(ref _data, newValue, oldValue) == oldValue)
- {
- break;
- }
+ Interlocked.Or(ref _data, bit);
+ }
+ else
+ {
+ Interlocked.And(ref _data, ~bit);
}
}
}
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ExecutionContext.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\IOCompletionCallback.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\IThreadPoolWorkItem.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Threading\Interlocked.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\LazyInitializer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\LazyThreadSafetyMode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\LockRecursionException.cs" />
if (!_frozenForEnqueues) // flag used to ensure we don't increase the Tail more than once if frozen more than once
{
_frozenForEnqueues = true;
-
- // Increase the tail by FreezeOffset, spinning until we're successful in doing so.
- int tail = _headAndTail.Tail;
- while (true)
- {
- int oldTail = Interlocked.CompareExchange(ref _headAndTail.Tail, tail + FreezeOffset, tail);
- if (oldTail == tail)
- {
- break;
- }
- tail = oldTail;
- }
+ Interlocked.Add(ref _headAndTail.Tail, FreezeOffset);
}
}
{
Debug.Assert(_fullyInitialized);
- // Attempt to set closed state (low order bit of the _state field).
- // Might have to attempt these repeatedly, if the operation suffers
- // interference from an AddRef or Release.
- int oldState, newState;
- do
- {
- oldState = _state;
- newState = oldState | StateBits.Closed;
- } while (Interlocked.CompareExchange(ref _state, newState, oldState) != oldState);
+ // Set closed state (low order bit of the _state field).
+ Interlocked.Or(ref _state, StateBits.Closed);
GC.SuppressFinalize(this);
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.CompilerServices;
+using Internal.Runtime.CompilerServices;
+
+namespace System.Threading
+{
+ /// <summary>Provides atomic operations for variables that are shared by multiple threads.</summary>
+ public static partial class Interlocked
+ {
+ #region Increment
+ /// <summary>Increments a specified variable and stores the result, as an atomic operation.</summary>
+ /// <param name="location">The variable whose value is to be incremented.</param>
+ /// <returns>The incremented value.</returns>
+ /// <exception cref="NullReferenceException">The address of location is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [CLSCompliant(false)]
+ public static uint Increment(ref uint location) =>
+ Add(ref location, 1);
+
+ /// <summary>Increments a specified variable and stores the result, as an atomic operation.</summary>
+ /// <param name="location">The variable whose value is to be incremented.</param>
+ /// <returns>The incremented value.</returns>
+ /// <exception cref="NullReferenceException">The address of location is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [CLSCompliant(false)]
+ public static ulong Increment(ref ulong location) =>
+ Add(ref location, 1);
+ #endregion
+
+ #region Decrement
+ /// <summary>Decrements a specified variable and stores the result, as an atomic operation.</summary>
+ /// <param name="location">The variable whose value is to be decremented.</param>
+ /// <returns>The decremented value.</returns>
+ /// <exception cref="NullReferenceException">The address of location is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [CLSCompliant(false)]
+ public static uint Decrement(ref uint location) =>
+ (uint)Add(ref Unsafe.As<uint, int>(ref location), -1);
+
+ /// <summary>Decrements a specified variable and stores the result, as an atomic operation.</summary>
+ /// <param name="location">The variable whose value is to be decremented.</param>
+ /// <returns>The decremented value.</returns>
+ /// <exception cref="NullReferenceException">The address of location is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [CLSCompliant(false)]
+ public static ulong Decrement(ref ulong location) =>
+ (ulong)Add(ref Unsafe.As<ulong, long>(ref location), -1);
+ #endregion
+
+ #region Exchange
+ /// <summary>Sets a 32-bit unsigned integer to a specified value and returns the original value, as an atomic operation.</summary>
+ /// <param name="location1">The variable to set to the specified value.</param>
+ /// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
+ /// <returns>The original value of <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [CLSCompliant(false)]
+ public static uint Exchange(ref uint location1, uint value) =>
+ (uint)Exchange(ref Unsafe.As<uint, int>(ref location1), (int)value);
+
+ /// <summary>Sets a 64-bit unsigned integer to a specified value and returns the original value, as an atomic operation.</summary>
+ /// <param name="location1">The variable to set to the specified value.</param>
+ /// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
+ /// <returns>The original value of <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [CLSCompliant(false)]
+ public static ulong Exchange(ref ulong location1, ulong value) =>
+ (ulong)Exchange(ref Unsafe.As<ulong, long>(ref location1), (long)value);
+ #endregion
+
+ #region CompareExchange
+ /// <summary>Compares two 32-bit unsigned integers for equality and, if they are equal, replaces the first value.</summary>
+ /// <param name="location1">The destination, whose value is compared with <paramref name="comparand"/> and possibly replaced.</param>
+ /// <param name="value">The value that replaces the destination value if the comparison results in equality.</param>
+ /// <param name="comparand">The value that is compared to the value at <paramref name="location1"/>.</param>
+ /// <returns>The original value in <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [CLSCompliant(false)]
+ public static uint CompareExchange(ref uint location1, uint value, uint comparand) =>
+ (uint)CompareExchange(ref Unsafe.As<uint, int>(ref location1), (int)value, (int)comparand);
+
+ /// <summary>Compares two 64-bit unsigned integers for equality and, if they are equal, replaces the first value.</summary>
+ /// <param name="location1">The destination, whose value is compared with <paramref name="comparand"/> and possibly replaced.</param>
+ /// <param name="value">The value that replaces the destination value if the comparison results in equality.</param>
+ /// <param name="comparand">The value that is compared to the value at <paramref name="location1"/>.</param>
+ /// <returns>The original value in <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [CLSCompliant(false)]
+ public static ulong CompareExchange(ref ulong location1, ulong value, ulong comparand) =>
+ (ulong)CompareExchange(ref Unsafe.As<ulong, long>(ref location1), (long)value, (long)comparand);
+ #endregion
+
+ #region Add
+ /// <summary>Adds two 32-bit unsigned integers and replaces the first integer with the sum, as an atomic operation.</summary>
+ /// <param name="location1">A variable containing the first value to be added. The sum of the two values is stored in <paramref name="location1"/>.</param>
+ /// <param name="value">The value to be added to the integer at <paramref name="location1"/>.</param>
+ /// <returns>The new value stored at <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [CLSCompliant(false)]
+ public static uint Add(ref uint location1, uint value) =>
+ (uint)Add(ref Unsafe.As<uint, int>(ref location1), (int)value);
+
+ /// <summary>Adds two 64-bit unsigned integers and replaces the first integer with the sum, as an atomic operation.</summary>
+ /// <param name="location1">A variable containing the first value to be added. The sum of the two values is stored in <paramref name="location1"/>.</param>
+ /// <param name="value">The value to be added to the integer at <paramref name="location1"/>.</param>
+ /// <returns>The new value stored at <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [CLSCompliant(false)]
+ public static ulong Add(ref ulong location1, ulong value) =>
+ (ulong)Add(ref Unsafe.As<ulong, long>(ref location1), (long)value);
+ #endregion
+
+ #region Read
+ /// <summary>Returns a 64-bit unsigned value, loaded as an atomic operation.</summary>
+ /// <param name="location">The 64-bit value to be loaded.</param>
+ /// <returns>The loaded value.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [CLSCompliant(false)]
+ public static ulong Read(ref ulong location) =>
+ CompareExchange(ref location, 0, 0);
+ #endregion
+
+ #region And
+ /// <summary>Bitwise "ands" two 32-bit signed integers and replaces the first integer with the result, as an atomic operation.</summary>
+ /// <param name="location1">A variable containing the first value to be combined. The result is stored in <paramref name="location1"/>.</param>
+ /// <param name="value">The value to be combined with the integer at <paramref name="location1"/>.</param>
+ /// <returns>The new value stored at <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int And(ref int location1, int value)
+ {
+ int current = location1;
+ while (true)
+ {
+ int newValue = current & value;
+ int oldValue = CompareExchange(ref location1, newValue, current);
+ if (oldValue == current)
+ {
+ return newValue;
+ }
+ current = oldValue;
+ }
+ }
+
+ /// <summary>Bitwise "ands" two 32-bit unsigned integers and replaces the first integer with the result, as an atomic operation.</summary>
+ /// <param name="location1">A variable containing the first value to be combined. The result is stored in <paramref name="location1"/>.</param>
+ /// <param name="value">The value to be combined with the integer at <paramref name="location1"/>.</param>
+ /// <returns>The new value stored at <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [CLSCompliant(false)]
+ public static uint And(ref uint location1, uint value) =>
+ (uint)And(ref Unsafe.As<uint, int>(ref location1), (int)value);
+
+ /// <summary>Bitwise "ands" two 64-bit signed integers and replaces the first integer with the result, as an atomic operation.</summary>
+ /// <param name="location1">A variable containing the first value to be combined. The result is stored in <paramref name="location1"/>.</param>
+ /// <param name="value">The value to be combined with the integer at <paramref name="location1"/>.</param>
+ /// <returns>The new value stored at <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static long And(ref long location1, long value)
+ {
+ long current = location1;
+ while (true)
+ {
+ long newValue = current & value;
+ long oldValue = CompareExchange(ref location1, newValue, current);
+ if (oldValue == current)
+ {
+ return newValue;
+ }
+ current = oldValue;
+ }
+ }
+
+ /// <summary>Bitwise "ands" two 64-bit unsigned integers and replaces the first integer with the result, as an atomic operation.</summary>
+ /// <param name="location1">A variable containing the first value to be combined. The result is stored in <paramref name="location1"/>.</param>
+ /// <param name="value">The value to be combined with the integer at <paramref name="location1"/>.</param>
+ /// <returns>The new value stored at <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [CLSCompliant(false)]
+ public static ulong And(ref ulong location1, ulong value) =>
+ (ulong)And(ref Unsafe.As<ulong, long>(ref location1), (long)value);
+ #endregion
+
+ #region Or
+ /// <summary>Bitwise "ors" two 32-bit signed integers and replaces the first integer with the result, as an atomic operation.</summary>
+ /// <param name="location1">A variable containing the first value to be combined. The result is stored in <paramref name="location1"/>.</param>
+ /// <param name="value">The value to be combined with the integer at <paramref name="location1"/>.</param>
+ /// <returns>The new value stored at <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int Or(ref int location1, int value)
+ {
+ int current = location1;
+ while (true)
+ {
+ int newValue = current | value;
+ int oldValue = CompareExchange(ref location1, newValue, current);
+ if (oldValue == current)
+ {
+ return newValue;
+ }
+ current = oldValue;
+ }
+ }
+
+ /// <summary>Bitwise "ors" two 32-bit unsigned integers and replaces the first integer with the result, as an atomic operation.</summary>
+ /// <param name="location1">A variable containing the first value to be combined. The result is stored in <paramref name="location1"/>.</param>
+ /// <param name="value">The value to be combined with the integer at <paramref name="location1"/>.</param>
+ /// <returns>The new value stored at <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [CLSCompliant(false)]
+ public static uint Or(ref uint location1, uint value) =>
+ (uint)Or(ref Unsafe.As<uint, int>(ref location1), (int)value);
+
+ /// <summary>Bitwise "ors" two 64-bit signed integers and replaces the first integer with the result, as an atomic operation.</summary>
+ /// <param name="location1">A variable containing the first value to be combined. The result is stored in <paramref name="location1"/>.</param>
+ /// <param name="value">The value to be combined with the integer at <paramref name="location1"/>.</param>
+ /// <returns>The new value stored at <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static long Or(ref long location1, long value)
+ {
+ long current = location1;
+ while (true)
+ {
+ long newValue = current | value;
+ long oldValue = CompareExchange(ref location1, newValue, current);
+ if (oldValue == current)
+ {
+ return newValue;
+ }
+ current = oldValue;
+ }
+ }
+
+ /// <summary>Bitwise "ors" two 64-bit unsigned integers and replaces the first integer with the result, as an atomic operation.</summary>
+ /// <param name="location1">A variable containing the first value to be combined. The result is stored in <paramref name="location1"/>.</param>
+ /// <param name="value">The value to be combined with the integer at <paramref name="location1"/>.</param>
+ /// <returns>The new value stored at <paramref name="location1"/>.</returns>
+ /// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [CLSCompliant(false)]
+ public static ulong Or(ref ulong location1, ulong value) =>
+ (ulong)Or(ref Unsafe.As<ulong, long>(ref location1), (long)value);
+ #endregion
+ }
+}
if (enabled)
{
- // Atomically set the END_AWAIT_NOTIFICATION bit
+ // Atomically set the TASK_STATE_WAIT_COMPLETION_NOTIFICATION bit
bool success = AtomicStateUpdate(TASK_STATE_WAIT_COMPLETION_NOTIFICATION,
TASK_STATE_COMPLETED_MASK | TASK_STATE_COMPLETION_RESERVED);
Debug.Assert(success, "Tried to set enabled on completed Task");
}
else
{
- // Atomically clear the END_AWAIT_NOTIFICATION bit
- int flags = m_stateFlags;
- while (true)
- {
- int oldFlags = Interlocked.CompareExchange(ref m_stateFlags, flags & (~TASK_STATE_WAIT_COMPLETION_NOTIFICATION), flags);
- if (oldFlags == flags) break;
- flags = oldFlags;
- }
+ // Atomically clear the TASK_STATE_WAIT_COMPLETION_NOTIFICATION bit
+ Interlocked.And(ref m_stateFlags, ~TASK_STATE_WAIT_COMPLETION_NOTIFICATION);
}
}
// Otherwise, compute it normally.
bool isInClass = CharInClass(ch, set);
- // Determine which bits to write back to the array.
+ // Determine which bits to write back to the array and "or" the bits back in a thread-safe manner.
int bitsToSet = knownBit;
if (isInClass)
{
bitsToSet |= valueBit;
}
-
- // "or" the bits back in a thread-safe manner.
- while (true)
- {
- int oldValue = Interlocked.CompareExchange(ref slot, current | bitsToSet, current);
- if (oldValue == current)
- {
- break;
- }
-
- current = oldValue;
- }
+ Interlocked.Or(ref slot, bitsToSet);
// Return the computed value.
return isInClass;
public static partial class Interlocked
{
public static int Add(ref int location1, int value) { throw null; }
+ [System.CLSCompliant(false)]
+ public static uint Add(ref uint location1, uint value) { throw null; }
public static long Add(ref long location1, long value) { throw null; }
+ [System.CLSCompliant(false)]
+ public static ulong Add(ref ulong location1, ulong value) { throw null; }
+ public static int And(ref int location1, int value) { throw null; }
+ [System.CLSCompliant(false)]
+ public static uint And(ref uint location1, uint value) { throw null; }
+ public static long And(ref long location1, long value) { throw null; }
+ [System.CLSCompliant(false)]
+ public static ulong And(ref ulong location1, ulong value) { throw null; }
public static double CompareExchange(ref double location1, double value, double comparand) { throw null; }
public static int CompareExchange(ref int location1, int value, int comparand) { throw null; }
+ [System.CLSCompliant(false)]
+ public static uint CompareExchange(ref uint location1, uint value, uint comparand) { throw null; }
public static long CompareExchange(ref long location1, long value, long comparand) { throw null; }
+ [System.CLSCompliant(false)]
+ public static ulong CompareExchange(ref ulong location1, ulong value, ulong comparand) { throw null; }
public static System.IntPtr CompareExchange(ref System.IntPtr location1, System.IntPtr value, System.IntPtr comparand) { throw null; }
[return: System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("location1")]
public static object? CompareExchange(ref object? location1, object? value, object? comparand) { throw null; }
[return: System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("location1")]
public static T CompareExchange<T>(ref T location1, T value, T comparand) where T : class? { throw null; }
public static int Decrement(ref int location) { throw null; }
+ [System.CLSCompliant(false)]
+ public static uint Decrement(ref uint location) { throw null; }
public static long Decrement(ref long location) { throw null; }
+ [System.CLSCompliant(false)]
+ public static ulong Decrement(ref ulong location) { throw null; }
public static double Exchange(ref double location1, double value) { throw null; }
public static int Exchange(ref int location1, int value) { throw null; }
+ [System.CLSCompliant(false)]
+ public static uint Exchange(ref uint location1, uint value) { throw null; }
public static long Exchange(ref long location1, long value) { throw null; }
+ [System.CLSCompliant(false)]
+ public static ulong Exchange(ref ulong location1, ulong value) { throw null; }
public static System.IntPtr Exchange(ref System.IntPtr location1, System.IntPtr value) { throw null; }
[return: System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("location1")]
public static object? Exchange([System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("value")] ref object? location1, object? value) { throw null; }
[return: System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("location1")]
public static T Exchange<T>([System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("value")] ref T location1, T value) where T : class? { throw null; }
public static int Increment(ref int location) { throw null; }
+ [System.CLSCompliant(false)]
+ public static uint Increment(ref uint location) { throw null; }
public static long Increment(ref long location) { throw null; }
+ [System.CLSCompliant(false)]
+ public static ulong Increment(ref ulong location) { throw null; }
public static void MemoryBarrier() { }
public static void MemoryBarrierProcessWide() { }
+ public static int Or(ref int location1, int value) { throw null; }
+ [System.CLSCompliant(false)]
+ public static uint Or(ref uint location1, uint value) { throw null; }
+ public static long Or(ref long location1, long value) { throw null; }
+ [System.CLSCompliant(false)]
+ public static ulong Or(ref ulong location1, ulong value) { throw null; }
public static long Read(ref long location) { throw null; }
+ [System.CLSCompliant(false)]
+ public static ulong Read(ref ulong location) { throw null; }
}
public static partial class LazyInitializer
{
public class InterlockedTests
{
[Fact]
- public void IncrementDecrement_int()
+ public void InterlockedAdd_Int32()
{
+ int value = 42;
+ Assert.Equal(12387, Interlocked.Add(ref value, 12345));
+ Assert.Equal(12387, Interlocked.Add(ref value, 0));
+ Assert.Equal(12386, Interlocked.Add(ref value, -1));
+
+ value = int.MaxValue;
+ Assert.Equal(int.MinValue, Interlocked.Add(ref value, 1));
+ }
+
+ [Fact]
+ public void InterlockedAdd_UInt32()
+ {
+ uint value = 42;
+ Assert.Equal(12387u, Interlocked.Add(ref value, 12345u));
+ Assert.Equal(12387u, Interlocked.Add(ref value, 0u));
+ Assert.Equal(9386u, Interlocked.Add(ref value, 4294964295u));
+
+ value = uint.MaxValue;
+ Assert.Equal(0u, Interlocked.Add(ref value, 1));
+ }
+
+ [Fact]
+ public void InterlockedAdd_Int64()
+ {
+ long value = 42;
+ Assert.Equal(12387, Interlocked.Add(ref value, 12345));
+ Assert.Equal(12387, Interlocked.Add(ref value, 0));
+ Assert.Equal(12386, Interlocked.Add(ref value, -1));
+
+ value = long.MaxValue;
+ Assert.Equal(long.MinValue, Interlocked.Add(ref value, 1));
+ }
+
+ [Fact]
+ public void InterlockedAdd_UInt64()
+ {
+ ulong value = 42;
+ Assert.Equal(12387u, Interlocked.Add(ref value, 12345));
+ Assert.Equal(12387u, Interlocked.Add(ref value, 0));
+ Assert.Equal(10771u, Interlocked.Add(ref value, 18446744073709550000));
+
+ value = ulong.MaxValue;
+ Assert.Equal(0u, Interlocked.Add(ref value, 1));
+ }
+
+ [Fact]
+ public void InterlockedIncrement_Int32()
+ {
+ int value = 42;
+ Assert.Equal(43, Interlocked.Increment(ref value));
+ Assert.Equal(43, value);
+ }
+
+ [Fact]
+ public void InterlockedIncrement_UInt32()
+ {
+ uint value = 42u;
+ Assert.Equal(43u, Interlocked.Increment(ref value));
+ Assert.Equal(43u, value);
+ }
+
+ [Fact]
+ public void InterlockedIncrement_Int64()
+ {
+ long value = 42;
+ Assert.Equal(43, Interlocked.Increment(ref value));
+ Assert.Equal(43, value);
+ }
+
+ [Fact]
+ public void InterlockedIncrement_UInt64()
+ {
+ ulong value = 42u;
+ Assert.Equal(43u, Interlocked.Increment(ref value));
+ Assert.Equal(43u, value);
+ }
+
+ [Fact]
+ public void InterlockedDecrement_Int32()
+ {
+ int value = 42;
+ Assert.Equal(41, Interlocked.Decrement(ref value));
+ Assert.Equal(41, value);
+
List<Task> threads = new List<Task>();
int count = 0;
for (int i = 0; i < 10000; i++)
}
[Fact]
- public void IncrementDecrement_long()
+ public void InterlockedDecrement_UInt32()
+ {
+ uint value = 42u;
+ Assert.Equal(41u, Interlocked.Decrement(ref value));
+ Assert.Equal(41u, value);
+ }
+
+ [Fact]
+ public void InterlockedDecrement_Int64()
{
+ long value = 42;
+ Assert.Equal(41, Interlocked.Decrement(ref value));
+ Assert.Equal(41, value);
+
List<Task> threads = new List<Task>();
long count = 0;
for (int i = 0; i < 10000; i++)
Assert.Equal(0, count);
}
+ [Fact]
+ public void InterlockedDecrement_UInt64()
+ {
+ ulong value = 42u;
+ Assert.Equal(41u, Interlocked.Decrement(ref value));
+ Assert.Equal(41u, value);
+ }
+
+ [Fact]
+ public void InterlockedExchange_Int32()
+ {
+ int value = 42;
+ Assert.Equal(42, Interlocked.Exchange(ref value, 12345));
+ Assert.Equal(12345, value);
+ }
+
+ [Fact]
+ public void InterlockedExchange_UInt32()
+ {
+ uint value = 42;
+ Assert.Equal(42u, Interlocked.Exchange(ref value, 12345u));
+ Assert.Equal(12345u, value);
+ }
+
+ [Fact]
+ public void InterlockedExchange_Int64()
+ {
+ long value = 42;
+ Assert.Equal(42, Interlocked.Exchange(ref value, 12345));
+ Assert.Equal(12345, value);
+ }
+
+ [Fact]
+ public void InterlockedExchange_UInt64()
+ {
+ ulong value = 42;
+ Assert.Equal(42u, Interlocked.Exchange(ref value, 12345u));
+ Assert.Equal(12345u, value);
+ }
+
+ [Fact]
+ public void InterlockedCompareExchange_Int32()
+ {
+ int value = 42;
+
+ Assert.Equal(42, Interlocked.CompareExchange(ref value, 12345, 41));
+ Assert.Equal(42, value);
+
+ Assert.Equal(42, Interlocked.CompareExchange(ref value, 12345, 42));
+ Assert.Equal(12345, value);
+ }
+
+ [Fact]
+ public void InterlockedCompareExchange_UInt32()
+ {
+ uint value = 42;
+
+ Assert.Equal(42u, Interlocked.CompareExchange(ref value, 12345u, 41u));
+ Assert.Equal(42u, value);
+
+ Assert.Equal(42u, Interlocked.CompareExchange(ref value, 12345u, 42u));
+ Assert.Equal(12345u, value);
+ }
+
+ [Fact]
+ public void InterlockedCompareExchange_Int64()
+ {
+ long value = 42;
+
+ Assert.Equal(42, Interlocked.CompareExchange(ref value, 12345, 41));
+ Assert.Equal(42, value);
+
+ Assert.Equal(42, Interlocked.CompareExchange(ref value, 12345, 42));
+ Assert.Equal(12345, value);
+ }
+
+ [Fact]
+ public void InterlockedCompareExchange_UInt64()
+ {
+ ulong value = 42;
+
+ Assert.Equal(42u, Interlocked.CompareExchange(ref value, 12345u, 41u));
+ Assert.Equal(42u, value);
+
+ Assert.Equal(42u, Interlocked.CompareExchange(ref value, 12345u, 42u));
+ Assert.Equal(12345u, value);
+ }
+
+ [Fact]
+ public void InterlockedRead_Int64()
+ {
+ long value = long.MaxValue - 42;
+ Assert.Equal(long.MaxValue - 42, Interlocked.Read(ref value));
+ }
+
+ [Fact]
+ public void InterlockedRead_UInt64()
+ {
+ ulong value = ulong.MaxValue - 42;
+ Assert.Equal(ulong.MaxValue - 42, Interlocked.Read(ref value));
+ }
+
+ [Fact]
+ public void InterlockedAnd_Int32()
+ {
+ int value = 0x12345670;
+ Assert.Equal(0x02244220, Interlocked.And(ref value, 0x7654321));
+ Assert.Equal(0x02244220, value);
+ }
+
+ [Fact]
+ public void InterlockedAnd_UInt32()
+ {
+ uint value = 0x12345670u;
+ Assert.Equal(0x02244220u, Interlocked.And(ref value, 0x7654321));
+ Assert.Equal(0x02244220u, value);
+ }
+
+ [Fact]
+ public void InterlockedAnd_Int64()
+ {
+ long value = 0x12345670;
+ Assert.Equal(0x02244220, Interlocked.And(ref value, 0x7654321));
+ Assert.Equal(0x02244220, value);
+ }
+
+ [Fact]
+ public void InterlockedAnd_UInt64()
+ {
+ ulong value = 0x12345670u;
+ Assert.Equal(0x02244220u, Interlocked.And(ref value, 0x7654321));
+ Assert.Equal(0x02244220u, value);
+ }
+
+ [Fact]
+ public void InterlockedOr_Int32()
+ {
+ int value = 0x12345670;
+ Assert.Equal(0x17755771, Interlocked.Or(ref value, 0x7654321));
+ Assert.Equal(0x17755771, value);
+ }
+
+ [Fact]
+ public void InterlockedOr_UInt32()
+ {
+ uint value = 0x12345670u;
+ Assert.Equal(0x17755771u, Interlocked.Or(ref value, 0x7654321));
+ Assert.Equal(0x17755771u, value);
+ }
+
+ [Fact]
+ public void InterlockedOr_Int64()
+ {
+ long value = 0x12345670;
+ Assert.Equal(0x17755771, Interlocked.Or(ref value, 0x7654321));
+ Assert.Equal(0x17755771, value);
+ }
+
+ [Fact]
+ public void InterlockedOr_UInt64()
+ {
+ ulong value = 0x12345670u;
+ Assert.Equal(0x17755771u, Interlocked.Or(ref value, 0x7654321));
+ Assert.Equal(0x17755771u, value);
+ }
+
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotArm64Process))] // [ActiveIssue("https://github.com/dotnet/coreclr/issues/20215")]
public void MemoryBarrierProcessWide()
{
<Compile Include="$(BclSourcesRoot)\System\Runtime\Loader\AssemblyDependencyResolver.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\Remoting\Contexts\Context.cs" />
<Compile Include="$(BclSourcesRoot)\System\Security\DynamicSecurityMethodAttribute.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Threading\Interlocked.cs" />
+ <Compile Include="$(BclSourcesRoot)\System\Threading\Interlocked.Mono.cs" />
<Compile Include="$(BclSourcesRoot)\System\Threading\Monitor.cs" />
<Compile Include="$(BclSourcesRoot)\System\Threading\Overlapped.cs" />
<Compile Include="$(BclSourcesRoot)\System\Threading\PreAllocatedOverlapped.cs" />
namespace System.Threading
{
- public static class Interlocked
+ public static partial class Interlocked
{
[Intrinsic]
[MethodImplAttribute (MethodImplOptions.InternalCall)]