我们是否需要对多线程 x32 系统使用 lock 来读取或写入 uint32_t 变量

Do we need to use lock for multi-threaded x32 system for just reading or writing into a uint32_t variable

本文关键字:读取 uint32 变量 lock 是否 多线程 系统 x32 我们      更新时间:2023-10-16

我有一个问题: 考虑一个 x32 系统, 因此,对于uint32_t变量,系统是否以原子方式读取和写入它? 这意味着,读取或写入的整个操作可以在一个指令周期内完成。 如果是这种情况,那么对于多线程 x32 系统,我们不必使用锁来读取或写入 uint32_t 变量。 请确认我的理解。

只有当你在汇编程序中编写代码并选择适当的指令时,它才是原子的。使用更高级别的语言时,您无法控制将选择哪些指令。

如果你有一些像a = b;这样的C代码,那么生成的机器码可能是"将b加载到寄存器x","将寄存器x存储在a的内存位置",这是不止一条指令。如果在这两者之间执行的中断或其他线程使用相同的变量,则意味着数据损坏。假设另一个线程向a写入不同的值 - 那么当返回到原始线程时,该更改将丢失。

因此,您必须使用某种保护机制,例如_Atomic限定符、互斥锁或关键部分。

是的,需要使用锁或其他适当的机制,如原子学。

C11 5.1.2.4p4:

    如果两个表达式计算修改
  1. 内存位置,而另一个表达式读取或修改相同的内存位置,则两个表达式计算将发生冲突。

C11 5.1.2.4p25:

  1. 如果程序在不同线程中包含两个冲突的操作,其中至少一个不是原子的,并且两者都不会先于另一个发生,则程序的执行包含数据争用。任何此类数据争用都会导致未定义的行为。

此外,如果你有一个不可变限定的变量,那么C标准甚至根本不要求更改进入内存;除非你使用某种同步机制,否则数据竞争在优化程序中的跨度可能比人们最初认为的要长得多 - 例如写入可能完全无序等等。

锁的使用不仅仅是为了确保原子性,32 位变量已经以原子方式写入。

您的问题是保护同时写入:

int x = 0;
Function 1: x++;
Function 2: x++;

如果没有同步,x 可能会以 1 而不是 2 结尾,因为函数 2 可能在函数 1 修改 x 之前读取x = 0。最糟糕的是,它可能会随机发生或不随机发生(或在客户端的PC上(,因此调试很困难。

问题是变量不会立即更新。

每个处理器的核心都有自己的专用内存(L1 和 L2 缓存(。因此,如果您在两个不同内核上的两个不同线程中修改变量,例如x++- 则每个内核都会更新自己的x版本。

原子操作和互斥体确保这些变量与共享内存(RAM/L3缓存(同步。