在C ++队列中对读/写操作进行排序

时间:2016-04-13 19:34:47

标签: c++ multithreading c++11 caching mutex

假设我们有一个SyncQueue类,其实现如下:

class SyncQueue {
    std::mutex mtx;
    std::queue<std::shared_ptr<ComplexType> > m_q;
public:
    void push(const std::shared_ptr<ComplexType> & ptr) {
        std::lock_guard<std::mutex> lck(mtx);
        m_q.push(ptr);
    }
    std::shared_ptr<ComplexType> pop() {
        std::lock_guard<std::mutex> lck(mtx);
        std::shared_ptr<ComplexType> rv(m_q.front());
        m_q.pop();
        return rv;
    }
};

然后我们有这个使用它的代码:

SyncQueue q;

// Thread 1, Producer:
std::shared_ptr<ComplexType> ct(new ComplexType);
ct->foo = 3;
q.push(ct);

// Thread 2, Consumer:
std::shared_ptr<ComplexType> ct(q.pop());
std::cout << ct->foo << std::endl;

我确保在3打印时获得ct->foomtx提供指针本身的语义之前发生,但我不确定是否为ComplexType的内存说了什么。如果有保证,这是否意味着每个互斥锁(std::lock_guard<std::mutex> lck(mtx);)强制任何已修改的内存位置的完全缓存失效,直到独立内核的内存层次结构合并为止?

1 个答案:

答案 0 :(得分:2)

std :: mutex()符合Mutex要求(http://en.cppreference.com/w/cpp/concept/Mutex

  

在同一个互斥锁上执行m.unlock()之前的操作与此同步   锁定操作(相当于release-acquire std :: memory_order)

这里解释了

release-acquire(http://en.cppreference.com/w/cpp/atomic/memory_order

  

发布 - 获取订购

     

如果标记了线程A中的原子库   memory_order_release和线程B中的原子加载来自同一个   变量标记为memory_order_acquire,所有内存写入(非原子的)   发生在原子商店之前的事情   线程A的观点,在线程B中成为可见的副作用,   也就是说,一旦原子加载完成,线程B就可以保证   看到线程A写入内存的所有内容。

     

同步是   仅在释放和获取相同的线程之间建立   原子变量。其他线程可以看到不同的内存顺序   访问比同步线程中的任何一个或两个。

本节中的代码示例与您的代码示例非常相似。所以应该保证线程1中的所有写操作都会在push()中的互斥锁解锁之前发生。

当然,如果&#34; ct-&gt; foo = 3&#34;没有任何特殊的棘手意义,其中实际的赋值发生在另一个线程中:))

来自cppreference的wrt cache-invalidation:

  

在强烈排序的系统(x86,SPARC TSO,IBM大型机)上,   发布 - 获取订购对于大多数操作是自动的。   不会为此同步发出其他CPU指令   模式,只有某些编译器优化受到影响(例如   禁止编译器将非原子存储移动到原子之外   存储 - 释放或执行早于原子的非原子加载   负载获取)。在弱有序系统(ARM,Itanium,PowerPC)上,   必须使用特殊的CPU加载或内存栅栏指令。

所以它真的取决于架构。