Internally Synchronized Class
-
Multiple threads accessing the same memory location
- With modification
- Must be synchronized to prevent a data race
-
C++ STL containers need to be externally synchronized
- e.g. by locking a mutex before calling a member function
-
Our own types can provide internal synchronization
- An
std::mutexas a data member - The member functions lock the mutex before accessing the class's data
- They unlock the mutex after accessing the class's data
- An
Wrapper for std::vector
-
std::vectoracts as a memory location- We may need to lock a mutex before calling its member function
-
Alternatively, we could write an internally synchronized wrapper for it
-
A class which
- Has an
std::vectordata member - Has an
std::mutexdata member - Member functions which lock the mutex before accessing the
std::vector - Then unlock the mutex after accessing it
- Has an
-
An internally synchronized class
#include <functional>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
using namespace std::literals;
// Very simplistic thread-safe vector class
class Vector {
std::mutex mut; // Mutex as private class data member
std::vector<int> vec; // Shared data - mutex protects access to it
public:
void push_back(const int &i) {
mut.lock(); // Lock the mutex
vec.push_back(i); // Critical section
mut.unlock(); // Unlock the mutex
}
void print() {
mut.lock();
for (auto i : vec) {
std::cout << i << ", ";
}
mut.unlock();
}
};
void func(Vector &vec) {
for (int i = 0; i < 5; ++i) {
vec.push_back(i);
std::this_thread::sleep_for(50ms);
vec.print();
}
}
int main() {
Vector vec;
std::thread thr1(func, std::ref(vec));
std::thread thr2(func, std::ref(vec));
std::thread thr3(func, std::ref(vec));
thr1.join();
thr2.join();
thr3.join();
}