Short for “mutual exclusion”.
A mutex is a locking mechanism that is applied to a piece of code to make sure only one thread can execute it at a time. Unlike with atomic, other threads are blocked.
To activate the mutex, we need a lock like std::lock_guard<std::mutex> lock(mtx);.
One can think of a mutex as a door lock while the lock is the key.
class Websocket{
public:
std::deque<std::string> message_buffer;
std::mutex mtx;
void buffer_messages() {
std::lock_guard<std::mutex> lock(mtx);
message_buffer.push_back("A");
}
};
int main() {
Websocket ws;
for(int i=0; i<1000; i++) {
std::thread t1(&Websocket::buffer_messages, &ws);
std::thread t2(&Websocket::buffer_messages, &ws);
t1.join();
t2.join();
}
std::cout << "Size: " << ws.message_buffer.size() << '\n';
}
If we remove the mutex and and say t1 and t2 act at the exact same time, t1 could add an element while t2 also adds an element (without considering the element added by t1). If t2 is the last thread finishing the write operation, the element added by t1 would be missing. In the script above, removing the mutex would lead to a final size <2000.
atomic should be used with simple variable types (int, string, etc.). mutex is more adapted for variables like containers (map, queue, etc.).