简体   繁体   English

在 c++ 中增加变量值时的竞争条件

[英]Race condition when increase a variable value in c++

I was asked this question in an interview recently.我最近在接受采访时被问到这个问题。 The question is if we have a function that takes a reference of int i as parameter and only does i++ .问题是我们是否有一个 function 将 int i的引用作为参数并且只执行i++ There is no any thread synchronizations.没有任何线程同步。 Now in main function, we initialize variable i with 0, then we create 7 new threads to run the same function and pass the same variable i , and after all threads are joined, how many possible values the variable i has?现在在main function 中,我们将变量i初始化为 0,然后我们创建 7 个新线程来运行相同的 function 并传递相同的变量i ,在所有线程加入后,变量i有多少个可能的值? Thank you very much!非常感谢你!

I tried thinking about the instructions of doing i++ .我试着考虑执行i++的说明。 Like load , add and store instructions.loadaddstore指令。 Assume we're using g++ compiler and in Linux OS.假设我们正在使用g++编译器和 Linux 操作系统。

The code you describe has undefined behavior.您描述的代码具有未定义的行为。 The value of i is undefined. i的值未定义。 If you do compile and run the code and print i on the screen the output could be anything.如果您确实编译并运行代码并在屏幕上打印i ,则 output 可能是任何东西。 It could be 42 or "hello world" .它可以是42"hello world"

Perhaps the question was meant to tease you into considering how many different ways there are to have multiple threads increment i and how that could affect the output. However, when code has undefined behavior, then logical reasoning is futile.也许这个问题的目的是让您考虑有多少种不同的方法可以让多个线程递增i以及这会如何影响 output。但是,当代码具有未定义的行为时,逻辑推理是徒劳的。

On the other hand, if you care about what actually happens in the compiled code, then the only way to know that is to look at the compiler generated assembly.另一方面,如果您关心编译代码中实际发生了什么,那么了解这一点的唯一方法就是查看编译器生成的程序集。 What the resulting program does is undefined, but it certainly does something.结果程序做什么是不确定的,但它确实做了一些事情。 Though you can only know what that is after you compiled it and study the assembly.虽然你只有在编译它并研究汇编之后才能知道那是什么。 The C++ standard does not describe what such a program will do and whatever you get is not portable. C++ 标准没有描述这样的程序会做什么,你得到的任何东西都是不可移植的。

The specific instructions used to increment the variable depends on the instruction set, but unless using some kind of atomic increment, it will break down into load/add/store operations as you are describing.用于递增变量的具体指令取决于指令集,但除非使用某种原子递增,否则它将分解为您所描述的加载/添加/存储操作。 On x86 that might be done with a single inc instruction, but without locking it will still break down to internal load/add/store operations.在 x86 上,这可能是通过一条inc指令完成的,但如果没有锁定,它仍然会分解为内部加载/添加/存储操作。

You will want to look at the possible interleaving of those sequences.您将需要查看这些序列的可能交错。 The interleaving is caused by interruption of the non-atomic sequences.交织是由非原子序列的中断引起的。 Here is one possible such possible interleaving:这是一种可能的交错:

thread 1      thread 2
 load   
               load
               add
               store
 add
 store

That sequence will leave the variable incremented only once, by thread 1, because thread 2's increment operation is effectively ignored — thread 1 stores last so "wins".该序列将使变量仅由线程 1 递增一次,因为线程 2 的递增操作实际上被忽略了 — 线程 1 存储最后一个,因此“获胜”。 (Thread 2 started with the wrong value in some sense anyway, so thread 2's store has the same value (+1) as thread 1's store.) (从某种意义上说,线程 2 以错误的值开始,因此线程 2 的存储与线程 1 的存储具有相同的值 (+1)。)

So, on one extreme the answer would be that the variable will be incremented only by one.因此,在一个极端情况下,答案是变量只会增加 1。 On the other extreme, if each thread successfully increments without interruption of that sequence, then the variable would be incremented 7 times.在另一个极端,如果每个线程在不中断该序列的情况下成功递增,则变量将递增 7 次。 All intermediate values (incremented by 2-6) are also possible.所有中间值(增加 2-6)也是可能的。


Since there is no synchronization at all, we also have to consider the possibility that we observe the original 0 after the joins, though I think this is unlikely due to the natural synchronization of system calls involved in creating threads and joining them.由于根本没有同步,我们还必须考虑在连接后观察到原始 0 的可能性,但我认为这不太可能,因为创建线程和连接它们所涉及的系统调用是自然同步的。

As mentioned in other answers, there is UB.正如其他答案中提到的,有 UB。

Also, it is possible to have situations where this number isn't increased at all or incremented a few times (less than 7) or whatever else.此外,可能会出现此数字根本不增加或增加几次(小于 7)或其他任何情况。 Since it's not an atomic variable (the question didn't mention that) - it will yield very unstable/unpredictable results.因为它不是一个原子变量(问题没有提到) - 它会产生非常不稳定/不可预测的结果。 See/google for " memory model " for more explainations.有关更多解释,请参阅/google 以获取“ memory model ”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM