Skip to content

Instantly share code, notes, and snippets.

@milleniumbug
Created January 22, 2017 13:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save milleniumbug/731663ec039b9be0c2efd905beb2689d to your computer and use it in GitHub Desktop.
Save milleniumbug/731663ec039b9be0c2efd905beb2689d to your computer and use it in GitHub Desktop.
shared_resource<T>
#pragma once
#include <mutex>
#include <shared_mutex>
#include <type_traits>
#include <tuple>
template<typename Mutex = std::shared_timed_mutex>
struct Shared
{
typedef Mutex MutexType;
typedef std::shared_lock<MutexType> ReadLock;
typedef std::unique_lock<MutexType> WriteLock;
};
template<typename Mutex = std::mutex>
struct Unique
{
typedef Mutex MutexType;
typedef std::unique_lock<MutexType> ReadLock;
typedef std::unique_lock<MutexType> WriteLock;
};
namespace detail
{
struct AccessSharedResourceImpl;
}
template<typename Resource, typename ShareType = Shared<>>
class shared_resource
{
private:
mutable typename ShareType::MutexType mutex;
Resource resource;
shared_resource(const shared_resource& other, typename ShareType::ReadLock other_lock) :
resource(other.resource)
{
static_cast<void>(other_lock);
}
shared_resource(shared_resource&& other, typename ShareType::WriteLock other_lock) :
resource(std::move(other.resource))
{
static_cast<void>(other_lock);
}
friend class detail::AccessSharedResourceImpl;
public:
typedef ShareType share_type;
shared_resource(Resource&& resource) :
resource(std::move(resource))
{
}
shared_resource(const Resource& resource) :
resource(resource)
{
}
shared_resource(const shared_resource& other) :
shared_resource(other, typename ShareType::ReadLock(other.mutex))
{
}
shared_resource(shared_resource&& other) :
shared_resource(std::move(other), typename ShareType::WriteLock(other.mutex))
{
}
shared_resource()
{
}
shared_resource& operator=(const shared_resource& other)
{
if(this != &other)
{
typename ShareType::WriteLock lhs_lk(this->mutex, std::defer_lock);
typename ShareType::ReadLock rhs_lk(other.mutex, std::defer_lock);
std::lock(lhs_lk, rhs_lk);
using std::swap;
swap(this->resource, other.resource);
}
}
shared_resource& operator=(shared_resource&& other)
{
if(this != &other)
{
typename ShareType::WriteLock lhs_lk(this->mutex, std::defer_lock);
typename ShareType::WriteLock rhs_lk(other.mutex, std::defer_lock);
std::lock(lhs_lk, rhs_lk);
this->resource = std::move(other.resource);
}
}
};
namespace detail
{
template<typename T>
struct is_shared_resource : std::false_type {};
template<typename Resource, typename ShareType>
struct is_shared_resource<shared_resource<Resource, ShareType>> : std::true_type {};
template<typename T>
struct ReadAccess
{
T& ref;
typedef typename T::share_type::ReadLock lock_type;
};
template<typename T>
struct WriteAccess
{
T& ref;
typedef typename T::share_type::WriteLock lock_type;
};
template<std::size_t Size>
struct LockTupleImpl
{
template<typename Tup, std::size_t... index>
static void run(Tup&& tup, std::index_sequence<index...>)
{
std::lock(std::get<index>(std::forward<Tup>(tup))...);
}
};
template<>
struct LockTupleImpl<1>
{
template<typename Tup, std::size_t... index>
static void run(Tup&& tup, std::index_sequence<index...>)
{
std::get<0>(std::forward<Tup>(tup)).lock();
}
};
struct AccessSharedResourceImpl
{
template<typename... SharedResourceAccess, typename Function>
static auto access_shared_resource(Function&& f, SharedResourceAccess... shared_access) -> decltype(std::forward<Function>(f)(shared_access.ref.resource...))
{
std::tuple<typename SharedResourceAccess::lock_type...> locks(
typename SharedResourceAccess::lock_type(shared_access.ref.mutex, std::defer_lock)...);
detail::LockTupleImpl<sizeof...(shared_access)>::run(locks, std::make_index_sequence<sizeof...(shared_access)>());
return std::forward<Function>(f)(shared_access.ref.resource...);
}
};
}
template<typename T>
detail::ReadAccess<const T> read(const T& shared_resource)
{
static_assert(detail::is_shared_resource<T>::value, "the type passed must be a shared_resource");
return { shared_resource };
}
template<typename T>
detail::WriteAccess<T> write(T& shared_resource)
{
static_assert(detail::is_shared_resource<T>::value, "the type passed must be a shared_resource");
return { shared_resource };
}
template<typename... Args>
auto access_shared_resource(Args&&... args)
{
return detail::AccessSharedResourceImpl::access_shared_resource(std::forward<Args>(args)...);
}
#include "shared_resource.hpp"
#include <iostream>
#include <vector>
int main()
{
shared_resource<int> a = 5;
shared_resource<std::vector<int>> b;
access_shared_resource([](auto&& a, auto&& b)
{
b.push_back(a);
}, read(a), write(b));
std::cout << access_shared_resource([](auto&& b)
{
return b[0];
}, read(b));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment