c - 用户空间程序中的 "volatile"是否表示存在错误?

标签 c linux-kernel linux-device-driver

当我在谷歌上搜索“volatile”及其用户空间使用情况时,我发现了 Theodore Tso 和 Linus Torvalds 之间的邮件。根据这些大师的说法,在用户空间中使用“volatile”可能是一个错误?? Check discussion here

虽然他们有一些解释,但我实在是看不懂。谁能用一些简单的语言解释他们为什么这么说?我们不应该在用户空间使用 volatile 吗??

最佳答案

volatile告诉编译器每次读写都有一个可观察到的副作用;因此,编译器无法假设连续两次读取或两次写入具有相同的效果。

例如,通常情况下,如下代码:

int a = *x;
int b = *x;
if (a == b)
    printf("Hi!\n");

可以优化成:

printf("Hi!\n");

volatile 的作用是告诉编译器这些值可能来自程序控制之外的某个地方,因此它必须实际读取这些值并执行比较。

很多人错误地认为他们可以使用 volatile 来构建无锁数据结构,这将允许多个线程共享值,并且他们可以观察这些的效果其他线程中的值。

但是,volatile 没有说明不同线程如何交互,并且可以应用于可以在不同内核上缓存不同值的值,或者可以应用于不能原子化的值在单个操作中编写,因此如果您尝试使用 volatile 编写多线程或多核代码,您可能会遇到很多问题。

相反,您需要使用锁或其他一些标准并发机制在线程之间进行通信,或者使用 memory barriers , 或使用 C11/C++11 atomic typesatomic operations .锁确保整个代码区域对变量具有独占访问权限,如果您的值太大、太小或未对齐而无法在单个操作中以原子方式写入,则锁可以起作用,而内存屏障和原子类型和操作提供关于它们如何与 CPU 协作以确保缓存同步或读写以特定顺序发生的保证。

基本上,volatile 在与单个硬件寄存器交互时最有用,它可以在程序控制之外变化,但可能不需要任何特殊的原子操作来访问。或者可以用在signal handlers ,因为线程可能会被中断,并且处理程序运行,然后控制权在同一线程内返回,如果您想将标志传递给中断的代码,则需要使用 volatile 值。

但是如果你在线程之间做任何类型的同步,你应该使用锁或标准库提供的其他一些并发原语,或者真正知道你在做什么关于内存排序和使用内存屏障或原子操作。

关于c - 用户空间程序中的 "volatile"是否表示存在错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56015270/

相关文章:

c - 如何从/dev/xxxx读取数据?

c++ - 当 Matlab 中仅接受 Int32Ptr 时,以字符串形式返回错误号

c - 如何从子进程访问父进程的地址空间?

c - 从未分配的内存中读取是否安全?

linux - 在现有驱动程序上使用自定义驱动程序

linux - 如何在Linux驱动程序中实现轮询以通知FD关闭

c - 编译包含<math.h>的c代码时需要使用额外的选项

c - Netlink 导致内核 panic

c - 如何使用阅读链接

linux - grub 错误 15 : file not found