c++ - 在这种情况下, volatile 限定词重要吗?

标签 c++ c volatile

我在问题C++ volatile member functions的答案中看到了一个代码示例,演示了volatile限定词的用法,引用如下:

volatile int x;

int DoSomething() {
    x = 1;
    DoSomeOtherStuff();
    return x+1; // Don't just return 2 because we stored a 1 in x.  
                // Check to get its current value
}

我不知道volatile限定符是否对上述代码有任何影响。 x是一个全局变量,在对x进行写入和读取之间有一个函数调用,我们只读取一次x。编译器是否应该对x进行真正的读取(即使不是volatile)?

我认为这与以下情况不同:
volatile int x;

int DoSomething() {
    x = 1;
    while (x != 1)
        break;
}

在这种情况下,我们在写入x之后立即重复读取x,因此volatile对于获取由其他线程编写的x的最新值是必需的。

我对这些代码示例的理解不是很自信,如果我错了,请纠正我。

编辑(回复评论):对不起,我没有清楚说明我的问题。至于第一个代码段,我在质疑该代码是否是volatile可能用法(不是volatile的保证用法)的有效示例。我只是想知道,如果没有volatile,那么假设没有多线程或内存映射IO之类的其他非琐事,是否可以保证x中对DoSomeOtherStuff()的任何可能更改都可以反射(reflect)在return x+1中。因为如果保证没有volatile就可以工作,那么该示例就显得无关紧要,更不用说一些注释指出的volatile的平台相关性质了。但是,如果不能保证,那么恐怕我现有的某些代码可能无法按预期工作。
(我可能根本不应该放第二个代码段。)

最佳答案

volatile限定词从不改变含义
代码本身。除非编译器可以证明DoSomeOtherStuff()不会修改x,它必须重新读取x不管是volatile还是否。为了使volatile相关,x必须类似于内存映射的IO,
可能会在程序外部更改。如果我们想像是
每微秒递增的寄存器,例如:

int
MeasureExecutionTime()
{
    x = 0;
    DoSomeOtherStuff();
    return x;
}

将返回DoSomeOtherStuff中使用的时间;的
即使内联,也需要编译器重新加载它DoSomeOtherStuff,并看到它从未修改x

当然,在典型的台式机上,可能没有
任何内存映射的IO,如果有的话,它在 protected 内存中,
无法访问的地方。而且很多编译器并没有真正
生成必要的代码以使其正常运行。
因此,对于此类机器上的通用应用程序,
每次使用volatile确实没有任何意义。

编辑:

关于您的第二个代码段:通常实现的是,volatile不保证您获得的最新副本x。可以说,这不符合volatile,但这是g++,Sun CC和至少某些方式
VC++版本工作。编译器将发出负载
每次在循环中读取x的指令,但是硬件
可能会在管道中找到该值,并且不会传播
读取请求到内存总线。为了保证
重新读取后,编译器将不得不插入篱笆或
腹部指导。

也许更重要的是(因为迟早会
发生,以便值不会在管道中),此循环
该机制将用于等待,直到其他值写入
其他线程已稳定。除了挥发物没有
影响何时发生其他变量的读写。

要了解volatile,了解
引入目的。引入时
内存管道等未知,以及(C)标准
被忽略的线程(或具有共享内存的多个进程)。volatile的目的是允许支持内存映射
IO,写地址有外部后果,并且
连续读取并不总是读取相同的内容。有
绝不希望代码中的其他变量是
已同步。在线程之间通信时,通常
读取和写入所有共享变量的顺序,其中
很重要如果我做类似的事情:
globalPointer = new Xxx;

和其他线程可以访问globalPointer,这很重要Xxx的构造函数中的所有写入都变为
更改globalPointer的值之前可见
发生。为此,不仅globalPointer具有
成为volatile,还包括Xxx的所有成员,以及任何
可能使用的Xxx成员函数的变量,或任何数据
可通过Xxx中的指针访问。这根本不是
合理;您很快就会在其中拥有一切
程序volatile。即使这样,它也需要
编译器正确实现volatile,设置围栏或
每次访问均应提供相关的说明。 (FWIW:围栏或
孟巴指令可以增加存储时间
的访问权限是10或更多。)

这里的解决方案不是不稳定的,而是可以访问
指针(并且仅访问该指针)原子,使用atomic_loadatomic_store原语已添加到C++ 11。
这些原语确实会导致必要的围栏或腰部
使用说明;他们还告诉编译器不要动
它们之间的任何内存访问。这样就可以使用atomic_load在上面设置指针,将导致所有先前的内存写入
在写入指针之前对其他线程可见
变得可见(在读取线程使用的情况下atomic_read,当然-atomic_write确保所有
以前的写在所有
线程和atomic_read确保所有后续读取
将进入“普通”内存,而不是获取一些值(value)
已经在准备中)。

关于c++ - 在这种情况下, volatile 限定词重要吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21887594/

相关文章:

c - 在同一台机器上运行的 C 应用程序之间的套接字通信

java - 这个对象在监听器中修改是线程安全的吗?

c++ - volatile 和多线程 : is the following thread-safe?

c++ - 互斥体的存在是否有助于摆脱 volatile 关键字?

c++ - 为什么 ReadFile() 不返回 0 ?程序试图永远从管道中读取数据

c++ - 带有 std::error_code 的错误堆栈

c++ - 什么是 "Argument-Dependent Lookup"(又名 ADL,或 "Koenig Lookup")?

c++ - 如何将 Action 连接到 C++/Qt 中的值更改

c - 我真的不明白我们是如何得到这些输出的

java - 是否可以使用 Turbo C/C++ 编译器生成 DLL?