Skip to content

Instantly share code, notes, and snippets.

@ridiculousfish
Created June 3, 2022 01:12
Show Gist options
  • Save ridiculousfish/952ceb797165201ab1ab76aec940845f to your computer and use it in GitHub Desktop.
Save ridiculousfish/952ceb797165201ab1ab76aec940845f to your computer and use it in GitHub Desktop.
// An object wrapping a scoped lock and a value
// This is returned from owning_lock.acquire()
// Sample usage:
// owning_lock<string> locked_name;
// acquired_lock<string> name = name.acquire();
// name.value = "derp"
//
// Or for simple cases:
// name.acquire().value = "derp"
//
template <typename Data>
class acquired_lock : noncopyable_t {
template <typename T>
friend class owning_lock;
template <typename T>
friend class acquired_lock;
acquired_lock(std::mutex &lk, Data *v) : lock(lk), value(v) {}
acquired_lock(std::unique_lock<std::mutex> &&lk, Data *v) : lock(std::move(lk)), value(v) {}
std::unique_lock<std::mutex> lock;
Data *value;
public:
Data *operator->() { return value; }
const Data *operator->() const { return value; }
Data &operator*() { return *value; }
const Data &operator*() const { return *value; }
/// Implicit conversion to const version.
operator acquired_lock<const Data>() {
// We're about to give up our lock, don't hold onto the data.
const Data *cvalue = value;
value = nullptr;
return acquired_lock<const Data>(std::move(lock), cvalue);
}
/// Create from a global lock.
/// This is used in weird cases where a global lock protects more than one piece of data.
static acquired_lock from_global(std::mutex &lk, Data *v) { return acquired_lock{lk, v}; }
/// \return a reference to the lock, for use with a condition variable.
std::unique_lock<std::mutex> &get_lock() { return lock; }
};
// A lock that owns a piece of data
// Access to the data is only provided by taking the lock
template <typename Data>
class owning_lock {
// No copying
owning_lock &operator=(const scoped_lock &) = delete;
owning_lock(const scoped_lock &) = delete;
owning_lock(owning_lock &&) = default;
owning_lock &operator=(owning_lock &&) = default;
std::mutex lock;
Data data;
public:
owning_lock(Data &&d) : data(std::move(d)) {}
owning_lock(const Data &d) : data(d) {}
owning_lock() : data() {}
acquired_lock<Data> acquire() { return {lock, &data}; }
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment