Home > Net >  Is it safe to assume volatile semantics when reassigning a struct field with a volatile field inside
Is it safe to assume volatile semantics when reassigning a struct field with a volatile field inside

Time:02-11

Take a look at the example below:

struct MyStruct
{
     private volatile int _field;
     public void Set(int v) => _field = v;
}

class MyClass
{
    private MyStruct _myStruct;
    // is it same as _myStruct.Set(0)?
    public void SomeMethod() => _myStruct = new MyStruct();
}

Basically the question is whether reassigning the whole struct with a volatile field inside uses the same volatile semantics as assigning the field directly.

CodePudding user response:

The volatile prefix is implemented using a modreq compiler attribute, and is only enforced by the compiler if access is done directly through the field that is marked volatile.

ECMA-335 specification does not actually have any volatile attribute for fields as such, and the CLR does not enforce volatile access to such a field, so it is up to the compiler to issue a volatile. prefix in the generated IL. It only does this if you access the field directly.

You can see this easily by decompiling the following code

public class C {
    static s s1;
    static s s2;
    public void M() {
        s1 = new s();
        s2 = s1;
        s2.i = s1.i;
    }
}
struct s{
     public volatile int i;   
}
.class public auto ansi beforefieldinit C
    extends [System.Private.CoreLib]System.Object
{
    // Fields
    .field private static valuetype s s1
    .field private static valuetype s s2

    // Methods
    .method public hidebysig 
        instance void M () cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 47 (0x2f)
        .maxstack 8

        IL_0000: nop
        IL_0001: ldsflda valuetype s C::s1
        IL_0006: initobj s
        IL_000c: ldsfld valuetype s C::s1
        IL_0011: stsfld valuetype s C::s2
        IL_0016: ldsflda valuetype s C::s2
        IL_001b: ldsflda valuetype s C::s1
        IL_0020: volatile.
        IL_0022: ldfld int32 modreq([System.Private.CoreLib]System.Runtime.CompilerServices.IsVolatile) s::i
        IL_0027: volatile.
        IL_0029: stfld int32 modreq([System.Private.CoreLib]System.Runtime.CompilerServices.IsVolatile) s::i
        IL_002e: ret
    } // end of method C::M

    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x2080
        // Code size 8 (0x8)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [System.Private.CoreLib]System.Object::.ctor()
        IL_0006: nop
        IL_0007: ret
    } // end of method C::.ctor

} // end of class C

.class private sequential ansi sealed beforefieldinit s
    extends [System.Private.CoreLib]System.ValueType
{
    // Fields
    .field public int32 modreq([System.Private.CoreLib]System.Runtime.CompilerServices.IsVolatile) i

} // end of class s

Sharplab link

  • Related