仅锁定1次操作?

Roy*_*mir 5 .net c# multithreading .net-4.0

我一直在问自己:"为什么我只能使用锁定一个声明"......

(恕我直言 - 如果它的1次操作只是作为一项任务 - 所以不应该有问题......)?

然后我看到了这个:

作为一项基本规则,您需要锁定访问任何可写共享字段.即使在最简单的情况下 - 对单个字段进行分配操作 - 您也必须考虑同步.在下面的类中,Increment和Assign方法都不是线程安全的:

class ThreadUnsafe
{
  static int _x;
  static void Increment() { _x++; }  
  static void Assign() { _x = 123; }
}
Run Code Online (Sandbox Code Playgroud)

你能告诉我为什么这不是线程安全吗?我一直在运行许多脚本,无法找到任何问题......

Hei*_*nzi 4

这是一个示例,说明为什么您的示例不是线程安全的。最初,_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)
Run Code Online (Sandbox Code Playgroud)

_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
Run Code Online (Sandbox Code Playgroud)

结果就是现在100。基本上,锁确保两个锁定的块不会重叠。