g.p*_*dou 1 .net c# multithreading
我有一个属性类型很长的属性(Int64).
如果它是一个int,那么我可以将支持字段声明为:
private volatile int _myInt;
Run Code Online (Sandbox Code Playgroud)
并创建一个简单的get和set访问器.
但是,即使使用x64项目设置,C#编译器也不允许使用类型为long的volatile关键字.所以情况是,即使我们确定读/写操作在这个变量上都是原子的,不幸的是,读取变量的线程有可能获得并使用旧的方式(处理器或CLR/JIT优化器)缓存值...
问题1:这是否意味着我不必简单地在get访问器中读取此值,而是使用Interlocked来防止读取缓存值?
get
{
return Interlocked.CompareExchange(ref _myLong, 0, 0);
}
Run Code Online (Sandbox Code Playgroud)
这意味着一个相当开销......
问题2:仍然假设有保证的64位架构,在集合访问器中是否足够简单,如:
set
{
_myLong = value;
}
Run Code Online (Sandbox Code Playgroud)
提前致谢
您可以使用System.Threading.Volatile类来解决此问题.例如:
class Example {
private long _prop;
public long prop {
get { return Volatile.Read(ref _prop); }
set { Volatile.Write(ref _prop, value); }
}
}
Run Code Online (Sandbox Code Playgroud)
虽然这看起来效率低下,但事实上它在x64处理器上生成了高效的代码.抖动具有Volatile类的内置知识,并直接将其转换为机器代码,而不是依赖于框架实现.x64抖动知道64位Intel/AMD处理器上的长度是原子的.例如:
static void Main(string[] args) {
var obj = new Example();
obj.prop = 42;
Console.WriteLine(obj.prop);
}
Run Code Online (Sandbox Code Playgroud)
生成此机器代码:
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
Run Code Online (Sandbox Code Playgroud)
并注意如何完全消除属性getter和setter,直接访问Example._prop字段.这就是你要找的东西.如果您曾在具有弱内存模型的处理器(如ARM)上运行此代码,那么它仍将正常工作,并根据此类处理器的要求生成相应的获取和释放语义.
| 归档时间: |
|
| 查看次数: |
300 次 |
| 最近记录: |