C 在发出克隆系统调用之前/之后是否应该包括内存屏障?

C 在发出克隆系统调用之前/之后是否应该包括内存屏障?,c,linux,multithreading,system-calls,memory-barriers,C,Linux,Multithreading,System Calls,Memory Barriers,我知道,当我使用pthread_create()时,会自动发出一个适当的内存屏障,以确保新线程在创建之前能够看到父线程进行的所有写入 但是,如果我在Linux上手动使用clone(),该怎么办?我应该自己包含一个完整的屏障,还是内核/glibc会为我解决这个问题?系统调用可以被视为内存屏障。作为一个非内联函数调用,clone()实际上是一个编译器屏障。这也和内核内部所做的任何事情一样是一个障碍,我假设它包括与运行新线程的任何内核的release-acquire-sync。唯一可能出错的方法是,如

我知道,当我使用
pthread_create()
时,会自动发出一个适当的内存屏障,以确保新线程在创建之前能够看到父线程进行的所有写入


但是,如果我在Linux上手动使用
clone()
,该怎么办?我应该自己包含一个完整的屏障,还是内核/glibc会为我解决这个问题?

系统调用可以被视为内存屏障。作为一个非内联函数调用,
clone()
实际上是一个编译器屏障。这也和内核内部所做的任何事情一样是一个障碍,我假设它包括与运行新线程的任何内核的release-acquire-sync。唯一可能出错的方法是,如果另一个内核只使用
mou-consume
风格的依赖项排序,就像Linux在非常小心控制的条件下在RCU中使用一样。“我很确定你不需要额外的障碍。@PeterCordes在链接时间优化的时代,非内联函数调用通常都是完整的编译器障碍,这是真的吗?”?(我确实认为,
clone
尤其如此,但这仅仅是因为它使用带内存缓冲的内联asm。)@JosephSible:Shared library函数不能内联到可执行文件中。特别是对于Glibc,您不能安全地构建一个支持LTO的静态
libc.a
。如果它是内联的,就不会是非内联函数调用。。。我的意思是不在asm中内联,而不仅仅是在单独的C源文件中定义。此外,最终的
syscall
包装器要么是用asm手工编写的,因此无法内联,要么是在任何无缺陷的libc中使用
内存
clobber(编译器屏障)的内联
asm
语句。@JosephSible即使对非
内联
函数的调用最终被内联,因此,它本身并不是编译器的障碍,除非函数是纯计算的,否则它将涉及某种转换到内核模式、汇编代码、,或者其他一些无法理解的东西,这些东西肯定会使编译器按照ABI的规定将所有外部可访问的对象放入它们的规范表示中。系统调用可以被视为内存障碍。如果是非内联函数调用,
clone()
实际上是编译器的障碍。这也和内核内部所做的任何事情一样是一个障碍,我假设它包括与运行新线程的任何内核的release-acquire-sync。唯一可能出错的方法是,如果另一个内核只使用
mou-consume
风格的依赖项排序,就像Linux在非常小心控制的条件下在RCU中使用一样。“我很确定你不需要额外的障碍。@PeterCordes在链接时间优化的时代,非内联函数调用通常都是完整的编译器障碍,这是真的吗?”?(我确实认为,
clone
尤其如此,但这仅仅是因为它使用带内存缓冲的内联asm。)@JosephSible:Shared library函数不能内联到可执行文件中。特别是对于Glibc,您不能安全地构建一个支持LTO的静态
libc.a
。如果它是内联的,就不会是非内联函数调用。。。我的意思是不在asm中内联,而不仅仅是在单独的C源文件中定义。此外,最终的
syscall
包装器要么是用asm手工编写的,因此无法内联,要么是在任何无缺陷的libc中使用
内存
clobber(编译器屏障)的内联
asm
语句。@JosephSible即使对非
内联
函数的调用最终被内联,因此,它本身并不是编译器的障碍,除非函数是纯计算的,否则它将涉及某种转换到内核模式、汇编代码或其他不可理解的东西,这些东西肯定会使编译器将所有外部可访问的对象按照ABI的规定放在它们的规范表示中。