如何使用C ++ 11 atomics API防止在存储后重新排序负载?

时间:2014-11-26 00:20:50

标签: c++11 atomic

我知道您可以在生产者 - 消费者环境中使用C ++ 11 atomics API,以确保消费者看到"完成写作"只有在完全写出一些产生的记录之后才会标记,即

生产者:

data[write_index] = <something>
status[write_index].store(READABLE, std::memory_order_release)

消费者:

if (status[read_index].load(std::memory_order_acquire) == READABLE)
  //do something with data[read_index]

我的问题是接下来会发生什么 - 消费者如何安全地告诉生产者它已经从数据[read_index]读取完毕,以便生产者可以为了其他目的写入数据[read_index]?

在x86上,我能做到(我认为?)

消费者:

//do something with data[read_index] //LINE A
asm volatile("" : : : "memory"); //compiler barrier
status[read_index].store(AVAILABLE, std::memory_order_relaxed) //LINE B

生产者:

if (status[write_index].load(std::memory_order_relaxed) == AVAILABLE)
  //write_index is available for writing

我的印象是,在可以在商店之后重新排序负载的架构上,作者可以在LINE A完成之前观察LINE B,这会导致问题。

有没有办法使用C ++ 11 atomics API执行此操作? atomic_thread_fence说明看起来很有希望,但在阅读完文档之后,我并没有看到它提供了我需要的保证。

谢谢!

1 个答案:

答案 0 :(得分:0)

如果有疑问,请务必使用sequential consistency:)

  

memory_order_seq_cst   操作按顺序一致的方式排序:使用此内存顺序的所有操作都被命令发生一旦所有对所涉及的其他线程可能具有可见副作用的内存访问已经发生。   这是最严格的内存顺序,通过非原子内存访问保证线程交互之间最小的意外副作用。

它适用于将信号发送回生产者的消费者商店或者之前的std :: atomic_thread_fence。

void producer() {
  for(;;) {
    data[write_index] = <something>;
    status[write_index].store(READABLE, std::memory_order_release);
    // do something else while consumer reads it

    // producer knows for sure that reader will consume it and signal back
    while( status[write_index].load(std::memory_order_acquire) != WRITEABLE)
        _mm_pause(); // or at least std::this_thread::yield();
  }
}
void consumer() {
    while (status[read_index].load(std::memory_order_acquire) != READABLE)
        _mm_pause(); // or at least std::this_thread::yield();
    //do something with data[read_index]

    // signal back and prevent loads from reorder below
    status[read_index].store(WRITEABLE, std::memory_order_seq_cst);
}

我担心这会导致x86上的过度同步..但是在其他人提出更棘手(但仍然是可移植的C ++ 11)方法之前,请考虑这是可移植性的代价。