Mic*_*l P 1 c linux-device-driver linux-kernel
当我搜索“ volatile”及其用户空间使用情况时,发现了Theodore Tso和Linus Torvalds之间的邮件。根据这些大师的说法,在用户空间中使用“ volatile”可能是一个错误?在这里查看讨论
尽管他们有一些解释,但我真的听不懂。谁能用一些简单的语言来解释他们为什么这么说?我们不应该在用户空间中使用volatile?
volatile告诉编译器每次读写都有明显的副作用;因此,编译器无法对行中具有相同效果的两次读取或两次写入做出任何假设。
例如,通常,以下代码:
int a = *x;
int b = *x;
if (a == b)
printf("Hi!\n");
Run Code Online (Sandbox Code Playgroud)
可以优化为:
printf("Hi!\n");
Run Code Online (Sandbox Code Playgroud)
是什么volatile做的是告诉编译器这些值,在程序的控制范围之外的某处现身,所以它必须实际读取这些值并进行比较。
许多人误以为他们可以volatile用来构建无锁数据结构,从而允许多个线程共享值,并且可以观察到这些值在其他线程中的作用,这是错误的。
但是,volatile关于不同的线程如何交互,可以应用到可以在不同内核上以不同值缓存的值,或者可以应用于无法在单个操作中以原子方式写的值的内容,无可厚非。使用编写多线程或多核代码volatile,可能会遇到很多问题。
相反,您需要使用锁或其他标准并发机制在线程之间进行通信,或者使用内存屏障,或者使用C11 / C ++ 11 原子类型和原子操作。锁可确保整个代码区域都可以独占访问变量,如果您的值太大,太小或未对齐而无法在单个操作中以原子方式写入,则可以使用该变量,而内存屏障和原子类型并且操作为它们与CPU的工作方式提供了保证,以确保高速缓存同步或以特定顺序进行读写。
基本上,volatile当您与单个硬件寄存器进行接口连接时,结束通常最有用,它可以在程序控制范围之外变化,但可能不需要任何特殊的原子操作即可访问。或者可以在信号处理程序中使用它,因为一个线程可能会被中断,然后该处理程序运行,然后在同一线程内返回控件,因此volatile如果要将标志传达给被中断的代码,则需要使用一个值。
但是,如果您要在线程之间进行任何类型的同步,则应该使用标准库提供的锁或其他并发原语,或者真正了解您在内存排序方面的工作,并使用内存屏障或原子操作。