当重新分配内部有 易失性字段的结构体字段时,假设易失性语义是否安全?

Vla*_*lad 5 c# multithreading volatile thread-safety memory-barriers

看一下下面的例子:

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();
}
Run Code Online (Sandbox Code Playgroud)

基本上,问题是重新分配内部带有易失性字段的整个结构是否使用与直接分配字段相同的易失性语义。

Cha*_*ace 5

volatile前缀是使用modreq编译器属性实现的,并且仅当直接通过标记为 的字段进行访问时才由编译器强制执行volatile

ECMA-335 规范实际上没有任何volatile此类字段的属性,并且 CLR 不强制对此类字段进行易失性访问,因此由编译器volatile.在生成的 IL 中发出前缀。仅当您直接访问该字段时它才会执行此操作。

通过反编译以下代码,您可以轻松看到这一点

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;   
}
Run Code Online (Sandbox Code Playgroud)
.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
Run Code Online (Sandbox Code Playgroud)

夏普实验室链接