Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/274.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在有保证的64位体系结构上实现long属性的线程安全原子访问器的最佳方法_C#_.net_Multithreading - Fatal编程技术网

C# 在有保证的64位体系结构上实现long属性的线程安全原子访问器的最佳方法

C# 在有保证的64位体系结构上实现long属性的线程安全原子访问器的最佳方法,c#,.net,multithreading,C#,.net,Multithreading,我有一个属性,它的类型是long(Int64) 如果是int,那么我可以将支持字段声明为: private volatile int _myInt; 并创建一个简单的get和set访问器 但是,C#编译器不允许将volatile关键字与long类型一起使用,即使使用x64项目设置也是如此。因此,情况是,即使我们确信读/写操作在此变量上是原子的,但不幸的是,读取该变量的线程将获得并使用旧的(处理器或CLR/JIT优化器)缓存值 问题1:这是否意味着我必须使用Interlocked来防止读取缓存的

我有一个属性,它的类型是long(Int64)

如果是int,那么我可以将支持字段声明为:

private volatile int _myInt;
并创建一个简单的get和set访问器

但是,C#编译器不允许将volatile关键字与long类型一起使用,即使使用x64项目设置也是如此。因此,情况是,即使我们确信读/写操作在此变量上是原子的,但不幸的是,读取该变量的线程将获得并使用旧的(处理器或CLR/JIT优化器)缓存值

问题1:这是否意味着我必须使用Interlocked来防止读取缓存的值,而不是简单地在get访问器中读取该值

get
{
    return Interlocked.CompareExchange(ref _myLong, 0, 0);
}
这意味着相当高的开销

问题2:仍然假设一个有保证的64位体系结构,在set访问器中简单的赋值就足够了吗

set
{
    _myLong = value;
}
提前感谢

您可以使用来解决此问题。例如:

class Example {
    private long _prop;
    public long prop {
        get { return Volatile.Read(ref _prop); }
        set { Volatile.Write(ref _prop, value); }
    }
}
    static void Main(string[] args) {
        var obj = new Example();
        obj.prop = 42;
        Console.WriteLine(obj.prop);
    }
虽然这看起来效率低下,但实际上它在x64处理器上生成了高效的代码。jitter具有Volatile类的内置知识,并直接将其转换为机器代码,而不依赖于框架实现。x64抖动知道long在64位Intel/AMD处理器上是原子的。例如:

class Example {
    private long _prop;
    public long prop {
        get { return Volatile.Read(ref _prop); }
        set { Volatile.Write(ref _prop, value); }
    }
}
    static void Main(string[] args) {
        var obj = new Example();
        obj.prop = 42;
        Console.WriteLine(obj.prop);
    }
生成此机器代码:

00007FFA3DF43AB0  sub         rsp,28h                     ; setup stack frame
00007FFA3DF43AB4  lea         rcx,[7FFA3DF959B0h]         ; obj = new Example
00007FFA3DF43ABB  call        00007FFA9D5A2300  
00007FFA3DF43AC0  mov         qword ptr [rax+8],2Ah       ; obj.prop setter
00007FFA3DF43AC8  mov         rcx,qword ptr [rax+8]       ; obj.prop getter
00007FFA3DF43ACC  call        00007FFA9CD0CFD0            ; Console.WriteLine
00007FFA3DF43AD1  nop                                     ; alignment
00007FFA3DF43AD2  add         rsp,28h                     ; destroy stack frame
00007FFA3DF43AD6  ret                                     ; done
并注意如何完全消除属性getter和setter,直接访问示例。这就是你要找的。如果您曾经在具有弱内存模型的处理器(如ARM)上运行此代码,那么它仍然可以正常工作,并根据此类处理器的要求生成相应的获取和释放语义。

您可以使用来解决此问题。例如:

class Example {
    private long _prop;
    public long prop {
        get { return Volatile.Read(ref _prop); }
        set { Volatile.Write(ref _prop, value); }
    }
}
    static void Main(string[] args) {
        var obj = new Example();
        obj.prop = 42;
        Console.WriteLine(obj.prop);
    }
虽然这看起来效率低下,但实际上它在x64处理器上生成了高效的代码。jitter具有Volatile类的内置知识,并直接将其转换为机器代码,而不依赖于框架实现。x64抖动知道long在64位Intel/AMD处理器上是原子的。例如:

class Example {
    private long _prop;
    public long prop {
        get { return Volatile.Read(ref _prop); }
        set { Volatile.Write(ref _prop, value); }
    }
}
    static void Main(string[] args) {
        var obj = new Example();
        obj.prop = 42;
        Console.WriteLine(obj.prop);
    }
生成此机器代码:

00007FFA3DF43AB0  sub         rsp,28h                     ; setup stack frame
00007FFA3DF43AB4  lea         rcx,[7FFA3DF959B0h]         ; obj = new Example
00007FFA3DF43ABB  call        00007FFA9D5A2300  
00007FFA3DF43AC0  mov         qword ptr [rax+8],2Ah       ; obj.prop setter
00007FFA3DF43AC8  mov         rcx,qword ptr [rax+8]       ; obj.prop getter
00007FFA3DF43ACC  call        00007FFA9CD0CFD0            ; Console.WriteLine
00007FFA3DF43AD1  nop                                     ; alignment
00007FFA3DF43AD2  add         rsp,28h                     ; destroy stack frame
00007FFA3DF43AD6  ret                                     ; done

并注意如何完全消除属性getter和setter,直接访问示例。这就是你要找的。如果您曾经在内存模型较弱的处理器(如ARM)上运行过此代码,那么它仍然可以正常工作,并按照这样的处理器的要求生成相应的获取和释放语义。

许多著名的C#luminaries过去都曾谈到过此类问题,我不敢把自己的任何话告诉他们(因此,很抱歉,没有提供摘要。)请访问这些luminaries博客文章并欣赏,等等。我会让其他人添加到其他博客文章的链接。@rwong:我已经仔细阅读了您提供的链接。虽然它很清楚,并且根据我的判断都是正确的,但它并没有说明我所暴露的问题。另外,我的问题是一个关于性能的实施问题d正确性,而非理论性。许多著名的C#名人过去都曾就此类问题发表过意见,我不敢向他们说任何我自己的话(因此,很抱歉,没有提供总结)请访问这些luminaries博客文章并欣赏,等等。我会让其他人添加到其他博客文章的链接。@rwong:我已经仔细阅读了您提供的链接。虽然它很清楚,并且根据我的判断都是正确的,但它并没有说明我所暴露的问题。另外,我的问题是一个关于性能的实施问题d正确性和非理论性。详细信息请参阅Thx。这肯定是我所缺少的知识,您能解释一下如何读取内存位置(mov rcx、qword ptr…)确保读取最新的值,我的意思是它是如何使处理器数据缓存无效的?嗯,这不是你要求的。简单地使用获得该保证的lock语句。看到这个机器代码,我真正不理解的是,围栏在哪里?最终的代码不应该产生与volatile关键字doe相同的语义吗s?(我是指Volatile.Read()和Volatile.Write())确实如此。请阅读底部的部分,“如果您曾经在内存模型较弱的处理器上运行此代码”.x64并不弱。当您显式使用volatile.Thx时,请尝试查看机器代码以了解详细信息。这肯定是我所缺少的知识,您能否解释如何读取内存位置(mov rcx、qword ptr…)确保读取最新的值,我的意思是它是如何使处理器数据缓存无效的?嗯,这不是你要求的。简单地使用获得该保证的lock语句。看到这个机器代码,我真正不理解的是,围栏在哪里?最终的代码不应该产生与volatile关键字doe相同的语义吗s?(我是指Volatile.Read()和Volatile.Write())确实如此。请阅读底部的部分,“如果您曾经在具有弱内存模型的处理器上运行此代码”。x64并不弱。显式使用Volatile时,请尝试查看机器代码。