Title here
Summary here
In this example, we’ll explore how to use mutexes to safely access data across multiple threads. This is useful for managing more complex state than can be handled by atomic operations.
#include <iostream>
#include <map>
#include <mutex>
#include <thread>
#include <vector>
// Container holds a map of counters; since we want to
// update it concurrently from multiple threads, we
// add a mutex to synchronize access.
class Container {
private:
std::mutex mu;
std::map<std::string, int> counters;
public:
// Lock the mutex before accessing counters; unlock
// it at the end of the function using a lock_guard
// for exception safety.
void inc(const std::string& name) {
std::lock_guard<std::mutex> lock(mu);
++counters[name];
}
// Method to get the current state of counters
std::map<std::string, int> getCounters() {
std::lock_guard<std::mutex> lock(mu);
return counters;
}
};
int main() {
// Note that the mutex is automatically initialized
Container c;
c.inc("a"); // Initialize "a" to 1
c.inc("b"); // Initialize "b" to 1
// This function increments a named counter
// in a loop.
auto doIncrement = [&c](const std::string& name, int n) {
for (int i = 0; i < n; ++i) {
c.inc(name);
}
};
// Run several threads concurrently; note
// that they all access the same Container,
// and two of them access the same counter.
std::vector<std::thread> threads;
threads.emplace_back(doIncrement, "a", 9999);
threads.emplace_back(doIncrement, "a", 9999);
threads.emplace_back(doIncrement, "b", 9999);
// Wait for the threads to finish
for (auto& t : threads) {
t.join();
}
// Print the final state of the counters
for (const auto& pair : c.getCounters()) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
return 0;
}
Running the program shows that the counters are updated as expected:
$ g++ -std=c++11 -pthread mutexes.cpp -o mutexes
$ ./mutexes
a: 20000
b: 10000
In this C++ version:
std::mutex
for synchronization and std::lock_guard
for exception-safe locking.Container
class encapsulates the mutex and the map of counters.doIncrement
, capturing the container by reference.std::thread
and joined at the end of main()
.getCounters()
method is added to safely access the final state of the counters.This example demonstrates how to use mutexes to safely manage shared state across multiple threads in C++. Next, we could explore implementing similar functionality using only threads and message passing.