通过“Instance”访问“Toggle()”类是否是线程安全的?如果是,根据什么假设、规则等。如果不是,为什么以及如何解决?
不,它不是线程安全的。
基本上,两个线程可以同时运行该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
从我下面改变了,这有关系吗?如果是这样,您需要在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 和return
. 为了使这个假设真正正确,您需要在value
该代码块的持续时间内锁定。
所以你会这样做:
lock( value )
{
if(value == 0)
... // all your code here
return value;
}
然而
在 .NET 中,您只能锁定引用类型。Int32 是一个值类型,所以我们不能锁定它。
我们通过引入一个“虚拟”对象来解决这个问题,并将它锁定在我们想要锁定“值”的任何地方。
这就是本·谢尔曼所指的。