我有一个多个类使用的C#单例类.是通过线程安全Instance
的Toggle()
方法访问?如果是,通过什么假设,规则等.如果不是,为什么以及如何解决它?
public class MyClass { private static readonly MyClass instance = new MyClass(); public static MyClass Instance { get { return instance; } } private int value = 0; public int Toggle() { if(value == 0) { value = 1; } else if(value == 1) { value = 0; } return value; } }
Orion Edward.. 28
是通过'Instance'访问'Toggle()'类threadafe吗?如果是,通过什么假设,规则等.如果不是,为什么以及如何解决它?
不,这不是线程安全的.
基本上,两个线程可以同时运行该Toggle
函数,因此可能会发生这种情况
// thread 1 is running this code if(value == 0) { value = 1; // RIGHT NOW, thread 2 steps in. // It sees value as 1, so runs the other branch, and changes it to 0 // This causes your method to return 0 even though you actually want 1 } else if(value == 1) { value = 0; } return value;
您需要按照以下假设进行操作.
如果2个线程正在运行,它们可以并且将在任何点随机交错并相互交互.您可以在写入或读取64位整数或浮点数(在32位CPU上)的一半,另一个线程可以跳入并从您下面更改它.
如果2个线程永远不会访问任何共同点,那么无关紧要,但只要它们这样做,就需要防止它们踩到彼此的脚趾.在.NET中执行此操作的方法是使用锁.
您可以通过考虑以下事情来决定锁定的内容和位置:
对于给定的代码块,如果something
从我的下面改变了get 的值,那会有关系吗?如果愿意,您需要something
在代码的持续时间内将其锁定.
再看一遍你的例子
// we read value here if(value == 0) { value = 1; } else if(value == 1) { value = 0; } // and we return it here return value;
为了使它返回我们期望的内容,我们假设value
在read和the之间不会改变return
.为了使此假设实际上正确,您需要锁定value
该代码块的持续时间.
所以你这样做:
lock( value ) { if(value == 0) ... // all your code here return value; }
然而
在.NET中,您只能锁定引用类型.Int32是一种值类型,因此我们无法锁定它.
我们通过引入"虚拟"对象,并锁定解决这个那个地方,我们会想锁定"价值".
这就是Ben Scheirman所指的.
是通过'Instance'访问'Toggle()'类threadafe吗?如果是,通过什么假设,规则等.如果不是,为什么以及如何解决它?
不,这不是线程安全的.
基本上,两个线程可以同时运行该Toggle
函数,因此可能会发生这种情况
// thread 1 is running this code if(value == 0) { value = 1; // RIGHT NOW, thread 2 steps in. // It sees value as 1, so runs the other branch, and changes it to 0 // This causes your method to return 0 even though you actually want 1 } else if(value == 1) { value = 0; } return value;
您需要按照以下假设进行操作.
如果2个线程正在运行,它们可以并且将在任何点随机交错并相互交互.您可以在写入或读取64位整数或浮点数(在32位CPU上)的一半,另一个线程可以跳入并从您下面更改它.
如果2个线程永远不会访问任何共同点,那么无关紧要,但只要它们这样做,就需要防止它们踩到彼此的脚趾.在.NET中执行此操作的方法是使用锁.
您可以通过考虑以下事情来决定锁定的内容和位置:
对于给定的代码块,如果something
从我的下面改变了get 的值,那会有关系吗?如果愿意,您需要something
在代码的持续时间内将其锁定.
再看一遍你的例子
// we read value here if(value == 0) { value = 1; } else if(value == 1) { value = 0; } // and we return it here return value;
为了使它返回我们期望的内容,我们假设value
在read和the之间不会改变return
.为了使此假设实际上正确,您需要锁定value
该代码块的持续时间.
所以你这样做:
lock( value ) { if(value == 0) ... // all your code here return value; }
然而
在.NET中,您只能锁定引用类型.Int32是一种值类型,因此我们无法锁定它.
我们通过引入"虚拟"对象,并锁定解决这个那个地方,我们会想锁定"价值".
这就是Ben Scheirman所指的.
Ben指出,原始的补充不是线程安全的
使线程安全的一种简单方法是引入一个lock语句.例如.像这样:
public class MyClass { private Object thisLock = new Object(); private static readonly MyClass instance = new MyClass(); public static MyClass Instance { get { return instance; } } private Int32 value = 0; public Int32 Toggle() { lock(thisLock) { if(value == 0) { value = 1; } else if(value == 1) { value = 0; } return value; } } }