c# - 只锁定 1 个操作?

标签 c# .net multithreading .net-4.0

我一直在问自己:“为什么我应该只对一个语句使用锁”...

(恕我直言 - 如果它的 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。假设您并行运行 IncrementAssign。如果方法是线程安全的,则结果应该是 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/

相关文章:

c# - 所有用户的用户设置

c# - Entity Framework 核心过滤器 DbSet

c# - Unity 从资源中加载文本

c# - 以通用方式测试匿名类型的字段值

函数外的 Javascript 导致未捕获的引用异常

c# - 获取快照会减慢 UI - 需要线程吗?

c# - 获取当前运行的进程

.net - 在 Sitecore 中重写 URL 参数

multithreading - 为什么线程本地存储这么慢?

java - 为什么java ReentrantLock不抛出InterruptedException?