6

在 C 或 C++ 程序中,如果 2 个线程使用相同的全局变量,则需要通过互斥锁锁定 var。

但具体在哪些情况下?

  1. 线程 1:读取线程 2:读取
  2. 线程 1:写入 线程 2:读取
  3. 线程 1:写入 线程 2:写入

当然,您需要锁定案例 3,但其他 2 个案例是什么?案例 2(非原子操作)会发生什么?是否存在某种访问冲突或线程 2 是否只是获取旧值?我对此有点困惑,因为不能同时访问硬件级别的内存和寄存器(在普通 PC 硬件中)或者我们是否有某种并行 CPU 具有并行总线线路到并行 ram 芯片?

4

4 回答 4

8

想想在每种情况下可能会发生什么。让我们只考虑竞态条件:这很容易,并且足以让我们看到后果。

在情况1中,变量没有被修改,所以无论是哪个顺序,两个线程都会读取相同的值。所以基本上,这里没有错。

情况 2 和 3 更糟。假设您有一个竞争条件,并且不知道哪些线程将更早获得访问权限。这意味着:

情况2:所有操作结束后变量的值没问题(会是线程1写入的值),但是线程2可能会得到变量的旧值,这可能会导致崩溃,或其他问题.

对于情况 3:变量的最终值是不可预测的,因为它取决于哪个线程将最后执行写操作。

对于情况 2 和 3,也可能发生其中一个线程在变量处于不一致状态时会尝试访问该变量,最终可能会导致其中一个线程读取一些垃圾数据(即情况 2),甚至在完成所有操作后变量中的垃圾数据。

所以,是的,锁定案例 2 和 3。

于 2013-08-02T12:32:25.400 回答
3

锁定规则很简单:

如果您写入一个变量,同时由另一个线程访问,那么您需要正确的操作顺序(例如,通过锁定)。

使用这个简单的规则,我们可以轻松地评估每种情况:

  1. 无需写入,无需同步
  2. 写,并发访问,需要同步
  3. 写,并发访问,需要同步

如果你不锁定会发生什么?

好吧,正式地说,这是未定义的行为。意思是我们不知道。虽然唯一可能的回应确实有助于把握问题的严重程度。

在机器级别,可能发生的情况是:

  • 在读取的情况下:访问过时的值
  • 在读取的情况下:访问部分值(在您查看时仅更新一半)
  • 在写入的情况下:最终值是值的大杂烩(在位级别)

...并且我们不要忘记,每当您读取不正确的指针/大小时,都可能导致崩溃。

在编译器级别,编译器可以线程具有唯一访问权限一样进行优化。在这种情况下,它可能意味着:

  • 删除“冗余”读取:转换while (flag)if (flag) while (true)...
  • 删除“未使用”的写入
  • ...

内存栅栏和显式同步指令(使用互斥体引入)的存在阻止了这些优化。

于 2013-08-02T12:56:20.280 回答
2

规则很简单:如果一个对象被多个线程访问(读或写),并且被任何线程修改,那么所有 访问都需要同步。否则,您有未定义的行为。

于 2013-08-02T13:29:59.333 回答
0

它并不像看起来那么简单,除了两种情况:

  1. 当只有读者而没有作者时,你永远不需要同步。
  2. 当有多个线程写入并且其中至少一个正在执行读取-修改-写入操作(例如++x;)时,您总是需要同步,否则您将得到完全不可预测的结果。

在所有其他情况下,如果您至少有一个写入器和一个读取器(或多个写入器),您通常(除了极少数例外)需要同步访问,但不一定总是,也不总是以最严格的方式。

这在很大程度上取决于您需要什么保证。一些应用程序需要严格的线程顺序一致性(有时您甚至需要锁公平性)。如果某些应用程序在同一个线程中仅具有发生前发生的保证,它们将同样运行良好,但性能要好得多。然而,其他应用程序甚至不需要那么多,并且对轻松的操作或根本没有任何保证完全满意。

例如,工作线程的这个“典型”实现有一个 writer 和一个 reader:

// worker thread
running = true;
while(running) { task = pull_task(); execute(task); }

// main thread exit code
running = false;
join(workerthread);

这在没有任何同步的情况下工作得很好。是的,从迂腐的角度来说,它的值何时或如何改变是不确定的running,但实际上它没有区别。内存位置不可能有一些“随机”的中间值,并且更改是否在几十纳秒之前或之后变得可见并不重要,因为工作线程很可能无论如何都忙于执行任务,并且在最坏的情况下,它会在几毫秒后获取更改。最终,在下一次迭代中,工作线程接受更改并退出。
几年前在 Dobb 博士发表的 SPSC 快进队列采用了类似的原理,只是使用了指针。

GCC 文档中对许多不同的同步模式及其含义进行了全面而全面的阅读。

于 2013-08-02T15:23:15.120 回答