I'm looking to create a fast synchronization model to share a message queue between two threads. I'm looking at a class with one vector, a mutex, and a dirty flag like so.
#include <vector>
#include <mutex>
class SharedVector {
std::mutex vector_lock;
std::vector<int> vec;
volatile bool dirty = false;
void write(int a) {
std::unique_lock lock(vector_lock);
vector.push_back(a); // Step 1
dirty = true; // Step 2
}
void consume(std::vector<int>& container) {
if (dirty) {
std::unique_lock lock(vector_lock);
container = std::move(vec); // Invalidates original vec
dirty = false;
}
}
};
I'm under the assumption that this implementation is thread safe, even though the dirty flag is read outside of a lock, but I'm not sure. The reasoning behind this are
The dirty flag is guaranteed to only be written by one thread at a time, since all writes are inside an atomic section, behind a lock.
Although the dirty flag may be set to true (Step 2 in write()) before the vector is appended (Step 1), because of CPU instruction reordering, that should not be a problem since the consume() thread must wait until the lock is released by the write() thread.
The write() thread should invalidate the dirty flag once it is written to, according to cache coherency protocols on x86, which I believe to be either MESI or MOESI.
Would anybody be able to tell me if this implementation is actually thread safe, or let me know if there are any downfalls to this? I am avoiding setting the dirty flag as atomic, since that has caused a significant slowdown which I am trying to avoid.
Edit:
A few constraints to this problem:
- There will only be one reader thread and one writer thread.
- The consume() function must be nonblocking, since the reader thread has other work to do if there are no messages available.