Let's assume we have a SyncQueue
class with the following implementation:
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;
}
};
then we have this code that uses it:
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;
Am I guaranteed to get 3
when ct->foo
is printed? mtx
provides happens-before semantics for the pointer itself, but I'm not sure that says anything for the memory of ComplexType
. If it is guaranteed, does it mean that every mutex lock (std::lock_guard<std::mutex> lck(mtx);
) forces full cache-invalidation for any modified memory locations up-till the place where memory hierarchies of independent cores merge?