#include <iostream>
#include <mutex>
#include <thread>
template <typename MUTEX, typename RESOURCE> class LockedResource
{
using my_type = LockedResource<MUTEX, RESOURCE>;
using mutex_t = MUTEX;
using type_t = RESOURCE;
using thread_id_t = std::thread::id;
mutex_t m_mutex;
type_t m_resource;
thread_id_t m_thread_id{};
public:
template <typename ... ARGS>
LockedResource(ARGS &&... args) :
m_resource(std::forward<ARGS>(args) ...)
{}
class Handler
{
using lock_t = std::unique_lock<mutex_t>;
lock_t m_lock;
type_t &m_resource;
thread_id_t &m_thread_id;
friend class LockedResource;
Handler(mutex_t &a_mutex, type_t &a_resource, thread_id_t a_thread_id) :
m_lock{a_mutex},
m_resource{a_resource},
m_thread_id{a_thread_id}
{}
public:
Handler(Handler &&a_handler) :
m_lock{std::move(a_handler.m_lock)},
m_resource{a_handler.m_resource},
m_thread_id{a_handler.m_thread_id}
{}
~Handler()
{
m_thread_id = {};
}
type_t *operator->() const
{
return &m_resource;
}
friend std::ostream &operator<<(std::ostream &o, const Handler &h) { return o << h.m_resource; }
};
Handler get() throw(std::runtime_error)
{
if (m_thread_id == std::this_thread::get_id())
{
using namespace std::string_literals;
throw std::runtime_error{"Double lock at "s.append(__PRETTY_FUNCTION__)};
}
return {m_mutex, m_resource, m_thread_id = std::this_thread::get_id()};
}
friend std::ostream &operator<<(std::ostream &o, my_type &lr) { return o << lr.get(); }
};
template <typename T> using Resource = LockedResource<std::mutex, T>;
#include <vector>
#include <string>
Resource<std::vector<int>> locked_vector{10, 10};
Resource<std::string> locked_string{"Hello world!"};
int main()
{
const auto &vec = locked_vector.get();
std::cout << vec->size() << '\n';
//locked_vector.get();
std::cout << locked_string << '\n';
return 0;
}