use*_*740 4 c# ref thread-safety
鉴于,
private object _x;
private object LoadAndSet(ref object x) {
// lock established over read and update
lock (somePrivateObjectNotUsedElsewhereThatIsIrrelvantToTheQuestion) {
if (x == null)
x = Load();
return x;
}
}
Run Code Online (Sandbox Code Playgroud)
调用为,
public object Load() {
return LoadAndSet(ref _x);
}
Run Code Online (Sandbox Code Playgroud)
_xlock也就是说,第一个代码等价于下面直接使用字段的地方吗?(赋值直接发生,而不是通过ref参数。)
private object _x;
private object LoadAndSetFieldDirectly() {
// lock established over read and update
lock (somePrivateObjectNotUsedElsewhereThatIsIrrelvantToTheQuestion) {
if (_x == null)
_x = Load();
return _x;
}
}
public object Load() {
return LoadAndSetFieldDirectly();
}
Run Code Online (Sandbox Code Playgroud)
我怀疑这是真的由于使用的ldind.ref和stind.ref在方法的MSIL; 然而,问题是在编写此类ref代码时需要有关线程安全(或缺乏)的权威文档/信息。
的语义lock(lockObject) { statements }是:
Monitor.Wait;这不是关于正确使用监视器对象的教程。)在控制离开区域之前,第二个线程不会进入受保护区域。(这是一个快速的非正式摘要;有关 C# 规范保证读取和写入重新排序的确切细节,请参阅规范。)
无论锁体中访问的变量是字段、局部变量、普通形式参数、引用/输出形式参数、数组元素还是指针解引用,这些语义都由运行时强制执行。
也就是说,有三件事让我对你的代码感到紧张。
首先,对现有机制进行不必要且次优的重新发明。如果要实现延迟初始化,请使用Lazy<T>. 当您可以使用由已经充分发挥其性能的专家编写的代码时,为什么要自己动手并冒犯错的风险呢?
其次,您必须确保该字段的每次使用都处于锁定状态,而不仅仅是它的初始化。将字段作为ref参数传递会为该字段创建别名,现在您已经完成了验证是否在锁下更难使用该字段的工作。
第三,这里似乎有机会进行不必要的争论。如果两个不同的字段都由两个不同线程上的相同代码初始化怎么办?现在,当他们不需要时,他们正在争夺锁。
| 归档时间: |
|
| 查看次数: |
259 次 |
| 最近记录: |