即使对于一个简单的 2 线程通信示例,我也很难用 C11 atomic 和 memory_fence 风格来表达这一点,以获得正确的内存排序:
共享数据:
volatile int flag, bucket;
生产者线程:
while (true) {
int value = producer_work();
while (atomic_load_explicit(&flag, memory_order_acquire))
; // busy wait
bucket = value;
atomic_store_explicit(&flag, 1, memory_order_release);
}
消费者线程:
while (true) {
while (!atomic_load_explicit(&flag, memory_order_acquire))
; // busy wait
int data = bucket;
atomic_thread_fence(/* memory_order ??? */);
atomic_store_explicit(&flag, 0, memory_order_release);
consumer_work(data);
}
据我了解,上述代码将正确排序存储桶-> 标志存储-> 标志加载-> 从存储桶加载。但是,我认为从存储桶加载和用新数据重新写入存储桶之间仍然存在竞争条件。要在桶读取之后强制执行订单,我想我需要atomic_thread_fence()
在桶读取和以下 atomic_store 之间进行显式操作。不幸的是,似乎没有任何memory_order
论据可以对前面的负载强制执行任何操作,甚至memory_order_seq_cst
.
一个非常肮脏的解决方案可能是在消费者线程中重新分配bucket
一个虚拟值:这与消费者只读概念相矛盾。
在旧的 C99/GCC 世界中,我可以使用__sync_synchronize()
我认为足够强大的传统。
同步这种所谓的反依赖关系的更好的 C11 风格的解决方案是什么?
(当然我知道我应该更好地避免这种低级编码并使用可用的高级构造,但我想了解......)