Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
带有gcc内联程序集的volatile与编译器屏障_Gcc_Constraints_Inline Assembly - Fatal编程技术网

带有gcc内联程序集的volatile与编译器屏障

带有gcc内联程序集的volatile与编译器屏障,gcc,constraints,inline-assembly,Gcc,Constraints,Inline Assembly,在我们的产品中,我们有一个内联互斥实现,使用各种特定于平台和编译器的方法来实现特定于硬件的部分。对于一些试图“欺骗”的过度优化代码,我们的“规则”之一是,如果在互斥锁外部和内部访问变量,那么该变量必须声明为volatile。我认为这也适用于不透明互斥实现(例如pthread_mutex_lock/unlock),这引发了一场有趣的争论 有人断言这是编译器错误的迹象(特别是当互斥实现是内联的并且对编译器来说“不是不透明的”时)。我举了下面的例子来反驳这一点 int v = pSharedMem-&

在我们的产品中,我们有一个内联互斥实现,使用各种特定于平台和编译器的方法来实现特定于硬件的部分。对于一些试图“欺骗”的过度优化代码,我们的“规则”之一是,如果在互斥锁外部和内部访问变量,那么该变量必须声明为volatile。我认为这也适用于不透明互斥实现(例如pthread_mutex_lock/unlock),这引发了一场有趣的争论

有人断言这是编译器错误的迹象(特别是当互斥实现是内联的并且对编译器来说“不是不透明的”时)。我举了下面的例子来反驳这一点

int v = pSharedMem->myVariable ;

__asm__ __volatile__(( "isync" : : :"memory" ))

v = pSharedMem->myVariable ;
在这个LinuxPPC gcc代码片段中,编译器不知道isync的运行时效果,除了我们可以通过内存约束告诉它的以外。您会在互斥体获取的末尾发现这样一条isync指令,以防止在实际持有互斥体之前成功获取互斥体之后执行任何指令(因此,如果在isync之前执行了加载,则必须将其丢弃)

在这个代码片段中,我们有一个编译器屏障,它阻止了对代码的重写,就像下面的代码一样

int v = pSharedMem->myVariable ;
v = pSharedMem->myVariable ;

__asm__ __volatile__(( "isync" : : :"memory" ))

(即:volatile属性应禁止这两种编译器重新排序)

我们还有isync本身,它可以防止第一次在运行时重新排序(但我不认为它可以防止第二次排序,因为第二次排序没有那么有趣)


然而,我的问题是,如果myVariable没有声明为volatile,那么“memory”约束是否足以让gcc在isync之后重新加载“v”?我仍然倾向于为这种模式强制使用volatile,因为这种代码对于所有特定于平台的编译器内置代码来说太敏感了。这就是说,如果我们将讨论简化为GCC和这个代码片段,那么这个asm内存约束是否足以让代码通过一对加载而不是一个加载生成?

使用
asm\uuuuuuuuu volatile\uuuuuu
“内存”
clobber需要并将充当完整的重新排序屏障<变量上的代码>volatile是不必要的。事实上,如果您查看Linux内核的定义,它不使用任何
volatile
修饰符,并且完全依赖于具有适当构造的
\uuuu asm\uuuuuu volatile\uuu
语句


另一方面,我相信
volatile
本身实际上根本不禁止重新排序,只缓存和优化值,因此对于同步目的来说毫无价值。

是的,但我说的不是原子或锁字上的volatile,而是受互斥锁保护的数据。我也不是说volatile有任何同步值(即:同步是由互斥体提供的,我想知道受互斥体保护的数据)。如果数据也是在互斥体之外访问的,那么一旦获得互斥体,就需要volatile来强制重新加载值。下面是一些额外的上下文(产生这个问题的原始讨论)@Peeter:我几乎可以肯定那里的示例是错误的。任何非内联函数调用都会强制从内存中重新获取非本地数据,因为编译器无法确保函数没有指向该数据的简单指针并简单地将其写入,这可能发生在单线程情况下,并且在那里定义了语义。另一方面,无论是否使用volatile,代码都是不正确的,因为在某些平台上读取不是原子的。在访问共享变量而不锁定时,您需要使用特殊的同步原子操作。@Jan,调用非内联代码后重新获取的需要是正确的,但在这种情况下,只引用了一个无别名的局部变量“v”,我认为只要确保其值始终“刷新”,Peeter说的对,编译器的障碍是不够的。我也认为您必须限定在“v”本地文件中捕获的数据源
__asm__ __volatile__(( "isync" : : :"memory" ))

int v = pSharedMem->myVariable ;
v = pSharedMem->myVariable ;