多个线程访问一个变量

我在正在阅读的教科书中发现了这个问题。 解决方案也在下面给出。 我无法理解最小值是多少2.为什么线程不能读取0,所有其他线程都执行并写入1? 无论是1还是2,最后编写的线程还必须完成自己的循环?

int n = 0; int main(int argc, char **argv) { for (i = 0; i < 5; i++) { int tmp = n; tmp = tmp + 1; n = tmp; } return 0; } 

如果单个线程运行此应用程序,您可能希望最终输出为5.如果5个线程并行运行相同的循环,该怎么办? n可能具有的最大值和最小值是多少? 最大的应该是selfevident:25,从5个线程增加5个。 然而,关于最小可能值的推理更加困难。 提示:n可以小于5,但是由你决定原因。

解:

有五个线程运行这个五次迭代循环并且没有并发访问的保护,n可以达到的最低值是两个。 从最终结果向后工作时,了解如何达到此结果是最简单的。 对于最终输出为2,线程必须从n读取值1,递增它,然后写入2。 这意味着另一个线程写了一个,暗示它最初也读为零(这也是n的起始值)。 这解释了五个线程中的两个线程的行为。 但是,要发生此行为,必须覆盖其他三个线程的结果。 两个有效的执行可以实现这一点。 要么1)所有三个线程开始并在第一个线程读取零和写入一个之间完成执行,或者2)所有三个线程开始并在最终线程读取一个和写入两个之间完成执行。 两个执行顺序都有效。

假设每个线程都有一个本地i (即每个线程将运行5次迭代,无论如何),让我们尝试得到1作为结果。 这意味着写入值的最后一个线程必须在第5次迭代时为n读取0。 这种情况可能发生的唯一方法是,如果在该线程的第5次迭代开始时没有线程写入n ,但是该线程在其第5次迭代时该线程本身必须写入n ,因此不可能。

因此,最小可能的结果是2,其可以发生,例如,如下:写入n的最后一个线程已完成4次迭代,然后另一个线程写入1,最后一个线程在其第5次迭代开始时读取1,所有其他线程在最后一个线程之前完成所有迭代,最后最后一个线程完成第5次迭代,写入2。

免责声明 :我正在回答关于multithreading的概念性问题 – 正如其他人所指出的那样,如果提供的C代码按原样使用,缺乏primefaces性可能会导致未定义的行为和任意结果。 根据问题的“不言而喻”的最大数字案例,我猜测教科书的作者要么没有意识到这一点,要么正在使用类似C的伪代码来说明这个概念。 如果是前者,那么正确的答案就是这本书是错的,但我认为后一种情况下的答案也具有教育意义。

只需添加一些见解:使用+运算符在C中添加,减去等等不仅仅是1个操作。 在汇编级下,+操作由多个指令组成。 如果多个线程要访问一个变量并且这些指令存在错误的交错,那么最终结果可能是一个非常不正确的结果 – >这是我们需要诸如互斥锁,信号量和条件变量之类的东西的另一个原因。

最大的应该是selfevident:25,从5个线程增加5个。

完全错误。 无论如何说这都不应该被听(至少涉及线程的事情),期间。

  int tmp = n; tmp = tmp + 1; n = tmp; 

想象一下,CPU没有增量操作,但具有高效的“加10”操作和高效的“减9”操作。 在这样的CPU上, tmp = tmp + 1; 可以优化到tmp += 10; tmp -= 9; tmp += 10; tmp -= 9; 。 编译器还可以通过对n进行操作来完全优化tmp

所以这段代码可能相当于:

 n += 10; n -= 9; 

现在假设发生了这种情况:所有五个线程都加10,所以n现在是50.第一个线程读取50,其他四个线程减去9.第一个线程从读取的50个中减去9并写入41.所以当完成所有操作时, n是41。

因此,声称不言而喻的是完全错误的。 谁写的不理解C中的线程。

如果每个线程写一个1,那么最终值不能神奇地成为别的东西

也完全是完全错误的。 考虑一个CPU,通过先写0然后递增值来写1。 如果这发生在两个核心上,最终结果可能是2.这本教科书是由一个从根本上不理解线程和未定义行为的人编写的。

(我假设这本教科书并不局限于某些特殊的语境,其中所说的是真的。例如,它可能使用“类C”代码作为平台中立汇编语言的一种forms,它可能正在制作关于对齐整数具有特定保证的平台的假设。但如果是这样的话,它的教学内容根本不会转换为C代码而只适用于在规则与教科书假设相匹配的CPU上编写汇编代码的人。)

关键是线程正在共享相同的数据实例。 此外,似乎假设所有其他线程以相同的执行速率运行。

因此,当每个线程围绕循环(到达fori++部分)时,它们几乎同时递增,所以就好像编写了代码:

  for (i = 0; i < 5; i++, i++, i++, i++, i++) ... 

至少在给出最小迭代次数的极端情况下。