最近在阅读《Is Parallel Programming Hard, And, If So, What Can You Do About It?》,并重新审视此MPSC的一些实现。比较关键的共享内存开销在于MpscChannel的publishProducedUnsafe和releaseConsumedUnsafe里,为了同时做到不指令重排以及读取原子量,而使用的读改写方案。相较于原子读取和@fence(),此处没法做到等效优化。
@fence()的移除来自这个issue。经过对替代方案的分析,我认为因为外部工具的问题而移除重要的并行控制底层工具依然不是一个站得住脚的理由。C11的内存序语义有其固有问题,主要是其功能是不正交的,把内存可见性和指令可重排性捆绑到了一起,但这对于指令可重排性的控制不完备,导致需要fence作为补丁。为了让 TSan能够顺利画出可见性的关系图,强制要求所有的同步都必须绑定在具体的变量上,是为了成全一种不完备的语义进行表达能力的物理阉割,这种行为让我想起了rust。
所幸的是,有内联汇编就有一切可能。因此,一个可能的前进方向,是通过内联汇编的方式重新实现@fence,虽然除了x86的mfence,我不太可能考虑其他架构。老实说,在x86架构,即使所有内存序全部用seq_cst都不会有影响,然而这里把@fence变更为读改写却依然会产生影响,足见此处不可忽视。
最近在阅读《Is Parallel Programming Hard, And, If So, What Can You Do About It?》,并重新审视此MPSC的一些实现。比较关键的共享内存开销在于MpscChannel的
publishProducedUnsafe和releaseConsumedUnsafe里,为了同时做到不指令重排以及读取原子量,而使用的读改写方案。相较于原子读取和@fence(),此处没法做到等效优化。@fence()的移除来自这个issue。经过对替代方案的分析,我认为因为外部工具的问题而移除重要的并行控制底层工具依然不是一个站得住脚的理由。C11的内存序语义有其固有问题,主要是其功能是不正交的,把内存可见性和指令可重排性捆绑到了一起,但这对于指令可重排性的控制不完备,导致需要fence作为补丁。为了让 TSan能够顺利画出可见性的关系图,强制要求所有的同步都必须绑定在具体的变量上,是为了成全一种不完备的语义进行表达能力的物理阉割,这种行为让我想起了rust。所幸的是,有内联汇编就有一切可能。因此,一个可能的前进方向,是通过内联汇编的方式重新实现
@fence,虽然除了x86的mfence,我不太可能考虑其他架构。老实说,在x86架构,即使所有内存序全部用seq_cst都不会有影响,然而这里把@fence变更为读改写却依然会产生影响,足见此处不可忽视。