gpt4 book ai didi

c++ - 编译器有时可以缓存声明为 volatile 的变量吗

转载 作者:IT老高 更新时间:2023-10-28 23:14:44 32 4
gpt4 key购买 nike

据我所知,编译器从不优化声明为 volatile 的变量。但是,我有一个这样声明的数组。

volatile long array[8];

不同的线程对其进行读写。数组的元素仅由其中一个线程修改并由任何其他线程读取。但是,在某些情况下,我注意到即使我从线程修改元素,读取它的线程也不会注意到更改。它继续读取相同的旧值,就好像编译器已将其缓存在某个地方一样。但是编译器原则上不应该缓存 volatile 变量,对吗?那怎么会这样呢。

注意:我没有使用 volatile 进行线程同步,所以请不要再给我答案,例如使用锁或原子变量。我知道 volatile 、原子变量和互斥体之间的区别。另请注意,该架构是具有主动缓存一致性的 x86。此外,在它被另一个线程修改后,我读了足够长的时间。即使过了很长时间,读取线程也看不到修改后的值。

最佳答案

But compiler in principal should not cache a volatile variable, right?

不,编译器原则上每次读/写变量时都必须读/写变量的地址。

[编辑:至少,它必须这样做,直到实现认为该地址的值是“可观察的”。正如 Dietmar 在他的回答中指出的那样,一个实现可能会声明“无法观察到”正常的内存。对于使用调试器、mprotect 或标准范围之外的其他东西的人来说,这会让他们感到惊讶,但原则上它可以符合。]

在完全不考虑线程的 C++03 中,由实现来定义在线程中运行时“访问地址”的含义。像这样的细节被称为“内存模型”。例如,Pthreads 允许每个线程缓存整个内存,包括 volatile 变量。 IIRC,MSVC 保证适当大小的 volatile 变量是原子的,并且它将避免缓存(相反,它将刷新到所有内核的单个一致缓存)。它提供这种保证的原因是因为在英特尔上这样做相当便宜 - Windows 只真正关心基于英特尔的架构,而 Posix 则关心更奇特的东西。

C++11 为线程定义了一个内存模型,它说这是一个数据竞争(即 volatile 确保在一个线程中读取相对于另一个线程中的写入进行排序)。两个访问可以按特定顺序排序,按未指定顺序排序(标准可能会说“不确定顺序”,我不记得了),或者根本不排序。完全不排序是不好的——如果两个未排序访问中的任何一个是写入,那么行为是未定义的。

这里的关键是“我从一个线程修改一个元素,然后读取它的线程没有注意到变化”中隐含的“然后”。您假设操作是按顺序排列的,但事实并非如此。就读取线程而言,除非您使用某种同步,否则其他线程中的写入不一定发生。实际上比这更糟糕——你可能会从我刚刚写的内容中想到,只是未指定操作的顺序,但实际上具有数据竞争的程序的行为是未定义的。

关于c++ - 编译器有时可以缓存声明为 volatile 的变量吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12710336/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com