我一直在问自己:“为什么我应该只对一个语句使用锁”...
(恕我直言 - 如果它的 1 操作仅像一个赋值 - 那么应该不会有问题..)?
然后我看到了这个:
As a basic rule, you need to lock around accessing any writable shared field. Even in the simplest case—an assignment operation on a single field—you must consider synchronization. In the following class, neither the Increment nor the Assign method is thread-safe:
class ThreadUnsafe
{
static int _x;
static void Increment() { _x++; }
static void Assign() { _x = 123; }
}
你能告诉我为什么这不是线程安全的吗? 我在脑海中运行了很多脚本,但找不到任何问题...
最佳答案
这是一个示例,说明为什么您的示例不是线程安全的。最初,_x = 0
。假设您并行运行 Increment
和 Assign
。如果方法是线程安全的,则结果应该是 100
(如果在赋值之前执行递增)或 101
(如果在赋值之后执行递增)。
(编辑:注意每个线程都有自己的工作栈!)
Thread 1 (executing Increment) Thread 2 (executing Assign 100)
-----------------------------------------------------------------
read _x onto stack (= 0)
put 100 on top of stack
write top of stack to _x (= 100)
increment top of stack (= 1)
write top of stack to _x (= 1)
_x
现在是 1
,既不是 100
也不是 101
。
当然,也可能是你的自增方法被编译器编译成了单一的原子操作。但是你不能依赖它,除非你使用的编译器特别保证它。
如果使用锁,会发生以下情况:
Thread 1 (executing Increment) Thread 2 (executing Assign 100)
-----------------------------------------------------------------
lock (success)
read _x onto stack (= 0)
lock (lock already taken;
| wait until Thead 1's lock is released)
increment top of stack (= 1) |
write top of stack to _x (= 1) |
unlock |
+> (success)
put 100 on top of stack
write top of stack to _x (= 100)
unlock
现在的结果是 100
。基本上,锁定确保两个锁定的 block 不重叠。
关于c# - 只锁定 1 个操作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10579508/