Skip to content

Instantly share code, notes, and snippets.

@oconnor663
Created July 23, 2022 00:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oconnor663/69388350ef6e440e1f05ceb4b586b78a to your computer and use it in GitHub Desktop.
Save oconnor663/69388350ef6e440e1f05ceb4b586b78a to your computer and use it in GitHub Desktop.
Mutex as a container in C++
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
template <typename T> class MyMutex;
template <typename T> class MyMutexGuard;
template <typename T> class MyMutex {
friend class MyMutexGuard<T>;
private:
std::mutex m_mutex;
T m_data;
public:
// Construct by defaulting, copying, or moving a T.
MyMutex() {}
MyMutex(const T &data) : m_data(data) {}
MyMutex(T &&data) : m_data(std::move(data)) {}
// Obtain a lock guard, which is also a smart pointer to T.
MyMutexGuard<T> lock() {
return {this};
}
};
template <typename T> class MyMutexGuard {
friend class MyMutex<T>;
private:
std::unique_lock<std::mutex> m_guard;
T *m_data_ptr;
MyMutexGuard(MyMutex<T> *mymutex)
: m_guard(mymutex->m_mutex), m_data_ptr(&mymutex->m_data) {}
public:
T &operator*() {
return *m_data_ptr;
}
T operator->() {
return m_data_ptr;
}
};
int main() {
MyMutex<std::vector<int>> myvec;
// Spawn a couple threads to append to the vector.
std::vector<std::thread> thread_handles;
for (int i = 0; i < 2; i++) {
std::thread thread_handle([&]() {
// On each thread, append a million ints.
for (int n = 0; n < 1'000'000; n++) {
// BUG: This retains a reference without retaining the lock.
std::vector<int> &vec_ref = *myvec.lock();
vec_ref.push_back(n);
}
});
thread_handles.push_back(std::move(thread_handle));
}
for (auto &handle : thread_handles) {
handle.join();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment