在一个多线程程序中,其中 2 个线程 - 线程 1 - 将运行一个将整数变量增加 1000 次然后退出的循环 线程 2 - 将运行一个将整数变量减少 1000 次然后退出的循环
两个线程都在一个信号量上等待并大致同时启动,并被安排在大致相同的时间在不同的内核上运行。
两个线程都退出后,整数变量的值会为零吗?注意:不使用锁定(互斥锁等)
让我们假设 linux 和 x86 架构以及多核硬件。
如果将相同的整数声明为 volatile (C++) 会发生什么情况?
在一个多线程程序中,其中 2 个线程 - 线程 1 - 将运行一个将整数变量增加 1000 次然后退出的循环 线程 2 - 将运行一个将整数变量减少 1000 次然后退出的循环
两个线程都在一个信号量上等待并大致同时启动,并被安排在大致相同的时间在不同的内核上运行。
两个线程都退出后,整数变量的值会为零吗?注意:不使用锁定(互斥锁等)
让我们假设 linux 和 x86 架构以及多核硬件。
如果将相同的整数声明为 volatile (C++) 会发生什么情况?
不稳定与否,您不能期望任何特定的输出(范围 [-1000,1000] 除外)——即使是单个并发写入也可能破坏增量/减量的结果(即使在 CPU 级别也不是原子的)。
如果多个线程同时修改相同的内存位置,则程序会发生数据竞争,并且效果未定义。结果几乎可以是任何东西,假设你得到了一个结果。对于像整数类型这样的简单变量,原子将消除数据竞争并提供适当的同步。使用atomic_int
(也称为atomic<int>
)。
您将需要使用适当的原子,并可能使用完整的内存屏障。
volatile
在这种情况下不会为您做任何事情(足够好,您可以使用)。
整数读/写可能是原子的,也可能不是原子的。所以答案是否定的,结果不一定是 0。
递增和递减需要三个操作:从内存中取值,修改,写回内存。在大多数平台上,不能保证这三个操作都以原子方式执行,除非您使用 C++11 原子类型、编译器特定(或程序集)原子内在函数或锁特别请求它。
volatile
与线程同步无关;它只是确保内存访问实际发生并且相对于同一线程中的其他副作用正确排序。