Interlocked.CompareExchange with enum

I'm trying to use Interlocked.CompareExchange with this enum:

public enum State {
    Idle,
    Running,
    //...
}

The following code doesn't compile, but that's what I want do do:

if (Interlocked.CompareExchange(ref state, State.Running, State.Idle) != State.Idle) {
    throw new InvalidOperationException("Unable to run - not idle");
}

Sure I can use a int instead of the enum and use a property:

private int state = (int)State.Idle;
public State { get { return (State)state; } }

Then cast the enums to a int:

if (Interlocked.CompareExchange(ref state, (int)State.Running, (int)State.Idle) !=  (int)State.Idle) {
    throw new InvalidOperationException("Unable to run - not idle");
}

But are there better ways to do this?

To make it simple, no :-)

Sadly C#/.NET consider enums as full type, partially disconnected from their base type. Every time you try to do something "fancy" on an enum you encounter some barrier.

How to apply InterLocked.Exchange for Enum Types in C#?, public MyEnum Field // added for convenience { get { return (MyEnum)Interlocked .CompareExchange(ref _field, 0, 0); } set { Interlocked. Examples. The following code example demonstrates a thread-safe method that accumulates a running total. The initial value of the running total is saved, and then the CompareExchange method is used to exchange the newly computed total with the old total.

It's possible from IL, and it's possible to create a helper method for this that can be used from C#.

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;

static class CompareExchangeEnumImpl<T>
{
    public delegate T dImpl(ref T location, T value, T comparand);
    public static readonly dImpl Impl = CreateCompareExchangeImpl();

    static dImpl CreateCompareExchangeImpl()
    {
        var underlyingType = Enum.GetUnderlyingType(typeof(T));
        var dynamicMethod = new DynamicMethod(string.Empty, typeof(T), new[] { typeof(T).MakeByRefType(), typeof(T), typeof(T) });
        var ilGenerator = dynamicMethod.GetILGenerator();
        ilGenerator.Emit(OpCodes.Ldarg_0);
        ilGenerator.Emit(OpCodes.Ldarg_1);
        ilGenerator.Emit(OpCodes.Ldarg_2);
        ilGenerator.Emit(
            OpCodes.Call,
            typeof(Interlocked).GetMethod(
                "CompareExchange",
                BindingFlags.Static | BindingFlags.Public,
                null,
                new[] { underlyingType.MakeByRefType(), underlyingType, underlyingType },
                null));
        ilGenerator.Emit(OpCodes.Ret);
        return (dImpl)dynamicMethod.CreateDelegate(typeof(dImpl));
    }
}

public static class InterlockedEx
{
    public static T CompareExchangeEnum<T>(ref T location, T value, T comparand)
    {
        return CompareExchangeEnumImpl<T>.Impl(ref location, value, comparand);
    }
}

public enum Foo
{
    X,
    Y,
}

static class Program
{
    static void Main()
    {
        Foo x = Foo.X;
        Foo y = Foo.Y;
        y = InterlockedEx.CompareExchangeEnum(ref x, y, Foo.X);
        Console.WriteLine("x: " + x);
        Console.WriteLine("y: " + y);
    }
}

Output:

x: Y
y: X

This just forwards the arguments to the correct Interlocked.Exchange overload. It fails badly if T isn't really an enum type, or its underlying type doesn't have an Interlocked.Exchange overload.

The generated IL is verifiable, at least according to PEVerify, as can be checked by making this use AssemblyBuilder and saving the result to a file.

c# - Interlocked.CompareExchange with enum - - Sher, i'm trying use interlocked.compareexchange enum: public enum state { idle, running, // } the following code doesn't compile, that's want do: Performs an atomic compare-and-exchange operation on the specified values. The function compares two specified 32-bit values and exchanges with another 32-bit value based on the outcome of the comparison.

Interlocked operations on enum are no problem:

public enum State { Idle, Running }

unsafe State CompareExchange(ref State target, State v, State cmp)
{
    fixed (State* p = &target)
        return (State)Interlocked.CompareExchange(ref *(int*)p, (int)v, (int)cmp);
}

See my full answer and discussion at https://stackoverflow.com/a/5589515/147511

Casting enum to int in a ref parameter - MSDN, enum MyEnum. {. Value1,. Value2,. } class MyClass. {. private MyEnum _field;. public void SetField(MyEnum value). {. Interlocked.Exchange(ref� Interlocked.Add. When using Interlocked, forget all you know about addition, subtraction and assignment operators. Instead, you will use the Add, Increment, Decrement, Exchange and CompareExchange methods.

But are there better ways to do this?

I use a class instead of Enum:

public class DataCollectionManagerState
{
    public static readonly DataCollectionManagerState Off = new DataCollectionManagerState() { };
    public static readonly DataCollectionManagerState Starting = new DataCollectionManagerState() { };
    public static readonly DataCollectionManagerState On = new DataCollectionManagerState() { };

    private DataCollectionManagerState() { }

    public override string ToString()
    {
        if (this == Off) return "Off";
        if (this == Starting) return "Starting";
        if (this == On) return "On";

        throw new Exception();
    }
}

public class DataCollectionManager
{
    private static DataCollectionManagerState _state = DataCollectionManagerState.Off;

    public static void StartDataCollectionManager()
    {
        var originalValue = Interlocked.CompareExchange(ref _state, DataCollectionManagerState.Starting, DataCollectionManagerState.Off);
        if (originalValue != DataCollectionManagerState.Off)
        {
            throw new InvalidOperationException(string.Format("StartDataCollectionManager can be called when it's state is Off only. Current state is \"{0}\".", originalValue.ToString()));
        }

        // Start Data Collection Manager ...

        originalValue = Interlocked.CompareExchange(ref _state, DataCollectionManagerState.On, DataCollectionManagerState.Starting);
        if (originalValue != DataCollectionManagerState.Starting)
        {
            // Your code is really messy
            throw new Exception(string.Format("Unexpected error occurred. Current state is \"{0}\".", originalValue.ToString()));
        }
    }
}

Interlocked.CompareExchange con enum C#, Interlocked.CompareExchange con enum. Estoy tratando de usar Interlocked. CompareExchange con esta enumeraci�n: public enum State { Idle, Running, // }. Sets a single-precision floating point number to a specified value and returns the original value, as an atomic operation. Sets a single-precision floating point number to a specified value and returns the original value, as an atomic operation. public: static float Exchange(float % location1, float

Using System.Runtime.CompilerServices.Unsafe

Here's a pretty good related answer going into depth.

using System;
using System.Runtime.CompilerServices;
using System.Threading;

public static class InterlockedEx
{
    /// <summary>
    /// Enum equivalent of <see cref="Interlocked.CompareExchange(ref Int32, Int32, Int32)"/> and <see cref="Interlocked.CompareExchange(ref Int64, Int64, Int64)"/>
    /// </summary>
    public static TEnum CompareExchange<TEnum>(ref TEnum location, TEnum value, TEnum comparand)
        where TEnum : struct, Enum
    {
        return Unsafe.SizeOf<TEnum>() switch
        {
            // .NET does not support 1- and 2-byte atomic operations as there
            // is no common hardware support for that.
            4 => CompareExchange32Bit(ref location, value, comparand),
            8 => CompareExchange64Bit(ref location, value, comparand),
            _ => throw new NotSupportedException("Only enums with an underlying type of 4 bytes or 8 bytes are allowed to be used with Interlocked")
        };

        static TEnum CompareExchange32Bit(ref TEnum location, TEnum value, TEnum comparand)
        {
            int comparandRaw = Unsafe.As<TEnum, int>(ref comparand);
            int valueRaw = Unsafe.As<TEnum, int>(ref value);
            ref int locationRaw = ref Unsafe.As<TEnum, int>(ref location);
            int returnRaw = Interlocked.CompareExchange(ref locationRaw, valueRaw, comparandRaw);
            return Unsafe.As<int, TEnum>(ref returnRaw);
        }

        static TEnum CompareExchange64Bit(ref TEnum location, TEnum value, TEnum comparand)
        {
            long comparandRaw = Unsafe.As<TEnum, long>(ref comparand);
            long valueRaw = Unsafe.As<TEnum, long>(ref value);
            ref long locationRaw = ref Unsafe.As<TEnum, long>(ref location);
            long returnRaw = Interlocked.CompareExchange(ref locationRaw, valueRaw, comparandRaw);
            return Unsafe.As<long, TEnum>(ref returnRaw);
        }
    }
}

c# - Как преобразовать ref [enum type] в ref int?, Я хочу использовать Interlocked.CompareExchange с перечислимого типа, который наследует от междунар, например, так: public enum MyEnum : int { A, � Remarks. _InterlockedCompareExchange does an atomic comparison of the Destination value with the Comparand value. If the Destination value is equal to the Comparand value, the Exchange value is stored in the address specified by Destination.

C# Interlocked Exchange, public static float Time; float someValue = 123; Interlocked. it is actually possible to perform an atomic Exchange or CompareExchange on an enum or other� Volatility, Atomicity and Interlocking. Earlier, when introducing the topic of data races, I mentioned that there was a more subtle reason why the first attempt at the code wasn't thread-safe.

ServiceStack.OrmLite/SpecialConverters.cs at master � ServiceStack , while (!ReferenceEquals(. System.Threading.Interlocked.CompareExchange(ref enumTypeCache, newCache, snapshot), snapshot));. return enumKind;. }. interlocked compareexchange vs lock (5) All interlocked operations have direct support in the hardware. Interlocked operations and atomic data type are different things.. Atomic type is a library level feature.

Volatility, Atomicity and Interlocking, Volatility, Atomicity and Interlocking The Exchange and CompareExchange methods act on variables of type int , object or float ; the Increment and Decrement� Interlocked.Add. When using Interlocked, forget all you know about addition, subtraction and assignment operators. Instead, you will use the Add, Increment, Decrement, Exchange and CompareExchange methods.

Comments
  • What you show (treating it as an int and casting) is basically exactly what I do.
  • @MarcGravell: basically?
  • To be honest it's not really that big a deal. Personally I would just keep it as an enum but cast it before you do the exchange.
  • @James you can't do that; the field needs to be int to use it as ref in the call. You can't cast during a ref.
  • @James: That will kill the reason to use CompareExchange.
  • @DarthVader Why not? I haven't ever had a reason to use Interlocked.Exchange with enums, but I do have other cases where there's a clear and correct way to do something, CIL allows it, but C# doesn't. In that case, I don't think C# is the right tool for the job, so I don't use C#.
  • How naughty! But I love it and copied it straight into my code :) Now, can you also do a Thread.VolatileRead(myEnum)?
  • @EugeneBeresovsky Sure, I don't see why not. It should be easy to adapt my answer to handle that. There are a lot of other methods that could also make sense to add, I don't think it'll benefit SO to include all of them here in an answer. :)
  • This is often a good idea if the enum is controlling lots of things as a kind of strategy object. One symptom is lots of switches on the enum in different places.