为什么将函数参数标记为volatile

时间:2012-02-20 15:43:13

标签: c parameters volatile

我目前正在阅读PostgreSql代码。以下是缓冲区管理器的摘录:

static void WaitIO(volatile BufferDesc *buf);
static bool StartBufferIO(volatile BufferDesc *buf, bool forInput);
static void TerminateBufferIO(volatile BufferDesc *buf, bool clear_dirty,

我知道volatile关键字通常用于设备驱动程序和嵌入式系统。关键字有解释。

  

当在类型定义中使用关键字volatile时,它会向编译器指示它应该如何处理变量。它主要告诉编译器,由于程序外部的操作或当前执行行,变量的值可能随时发生变化。   (Source

那么为什么某些函数参数被声明为volatile?我不希望DMA改变指针位置。那么这里发生了什么?

5 个答案:

答案 0 :(得分:19)

volatile BufferDesc *buf表示buf 指向的数据是易失性的,而不是buf包含的指针是易失性的。 (那将是BufferDesc * volatile buf。)

来自the page you linked to

  

另一方面,如果你有一个指针变量,其中地址本身是易失性但指向的内存不是那么我们有:

int * volatile x;

更新:抱歉,我错过了您的部分问题:

  

那么为什么某些函数参数被声明为volatile?

大概是因为它指向的数据可能以编译器不一定知道的方式改变。 volatile关键字用于防止编译器应用优化,假设数据不会以其不知道的方式发生更改。

答案 1 :(得分:7)

  

我不希望DMA改变指针位置。

不是位置,但可能是内容。而这正是它的意义......

答案 2 :(得分:1)

数据库实现在访问文件时不依赖于OS缓冲区和缓存。他们更喜欢实现自己的缓存系统并直接访问物理磁盘上的文件,以解决可靠性问题:必须将数据刷新到物理磁盘。 (它们使用O_DIRECT选项直接访问物理磁盘。)

您向我们展示的3个功能让我想到了来自磁盘的数据的异步处理。 (StartBufferIO(),TerminatedBufferIO()等)。老实说,我不确定它们的用途是什么,但基于我对数据库实现的了解以及那些函数名称,我会说缓冲区内容可能会被“磁盘”本身修改为来自磁盘上文件的数据(或任何设备),因此需要被标记为易失性

此假设加入了您对 volatile 关键字通常用于设备驱动程序的常规解释:

答案 3 :(得分:0)

DMA不是使用“volatile”的唯一原因。它对多线程和共享内存应用程序也很有用,其中另一个线程可能会更改此代码引用的内存。我确信PostgreSql是多线程的,所以这可能是为什么在这里使用volatile的原因。

答案 4 :(得分:0)

编译器在优化时通常会做的一件事就是删除死代码,因此如果你使用一个永远不会读取的变量进行某些操作并且其结果是无用的编译器可能只是删除它,以及删除其余的操作这影响了它。当您调试代码时,这种行为可能非常烦人,您正在执行某种类型的benchamrks。如果您声明为volatile变量,则会向编译器发出警告,它可能被外部库或程序使用,以及关键字可能具有的其他含义。然后它永远不应该把它当作死代码。