c++ - 通过访问函数访问共享内存是否需要 `volatile`?

标签 c++ c embedded volatile

[edit] 对于背景阅读,要清楚,这就是我所说的:Introduction to the volatile keyword

在查看嵌入式系统代码时,我看到的最常见错误之一是线程/中断共享数据的 volatile 遗漏。但是我的问题是,当通过访问函数或成员函数访问变量时,不使用 volatile 是否“安全”?

一个简单的例子;在下面的代码中...

volatile bool flag = false ;
void ThreadA()
{
    ...
    while (!flag)
    {
        // Wait
    }
    ...
}

interrupt void InterruptB()
{
    flag = true ;
} 

...变量 flag 必须是 volatile 以确保不会优化 ThreadA 中的读取,但是如果通过函数读取标志,则...

volatile bool flag = false ;
bool ReadFlag() { return flag }
void ThreadA()
{
    ...
    while ( !ReadFlag() )
    {
        // Wait
    }
    ...
}

... flag 还需要是 volatile 吗?我意识到它是 volatile 并没有什么坏处,但我关心的是何时省略它并且没有发现遗漏;这会安全吗?

上面的例子很简单;在实际情况中(以及我询问的原因),我有一个包装 RTOS 的类库,因此有一个抽象类 cTask 派生任务对象。这种“事件”对象通常具有访问数据的成员函数,这些函数可以在对象的任务上下文中修改但从其他上下文访问;那么,将此类数据声明为 volatile 是否重要?

我真的对这些数据保证的内容感兴趣,而不是实际的编译器可能会做什么。我可能测试了许多编译器,发现它们永远不会优化通过访问器的读取,但有一天会发现一个编译器或编译器设置使这个假设不成立。例如,我可以想象,如果函数是内联的,那么这种优化对于编译器来说将是微不足道的,因为它与直接读取没有什么不同。

最佳答案

我对 C99 的解读是,除非您指定 volatile,否则实际访问变量的方式和时间由实现定义。如果您指定 volatile 限定符,那么代码必须按照 抽象机 的规则工作。

标准中的相关部分是:6.7.3 类型限定符( volatile 描述)和5.1.2.3 程序执行(抽象机器定义)。

一段时间以来,我知道许多编译器实际上都有启发式方法来检测何时应重新读取变量以及何时可以使用缓存拷贝。 Volatile 让编译器清楚地知道,对变量的每次访问实际上都应该是对内存的访问。如果没有 volatile,编译器似乎可以自由地从不重新读取变量。

顺便说一句,将访问封装在一个函数中并不会改变这一点,因为即使没有 inline 的函数也可能仍被当前编译单元中的编译器内联。

附:对于 C++,可能值得检查前者所基于的 C89。我手头没有 C89。

关于c++ - 通过访问函数访问共享内存是否需要 `volatile`?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3148319/

相关文章:

c++ - 如何将曲面网格变成多面体?

c - 我的进程仍然是守护进程吗?

c++ - switch 语句中的静态变量

c++ - 如何在 C++ 中丢弃 const

javascript - "Hello World"+ JS V8 + VS2010

C 库代码的正确命名约定

创建文件函数

linux - 无法锁链(端口权限不足)

c++ - STD 中的动态内存分配

C++ 屏幕截图 - 如何读取位图?