CnxSharedLock struct
#include <include/Cnx/sync/SharedLock.h>
CnxSharedLock
provides scoped non-exclusive (shared) locking of higher-level mutexes (eg CnxSharedMutex
, CnxSharedTimedMutex
) provided by Cnx. It allows for a simple, concise way to acquire the shared lock on a mutex and ensure that lock is released appropriately when the CnxSharedLock
exits scope.
To ensure that a CnxSharedLock
is appropriately destroyed when it leaves scope, releasing the lock on its associated mutex, declare it as a SharedLock
.
A CnxSharedLock
should never be copied, to do so is undefined behavior. A CnxSharedLock
may be moved into a new scope with move
(eg. passing it to a function as a parameter), however. If this is done though, the receiving function will need to either move the parameter into a local variable declared as a SharedLock
, or manually unlock the mutex before it returns.
Example:
// MyThing.h #include <Cnx/sync/SharedMutex.h> static MyType my_very_important_thing; static CnxSharedMutex* my_thing_mutex; void init_my_thing(void); void update_my_thing(u64 value); u64 get_value_from_my_thing(void); // MyThing.c #include <Cnx/Allocators.h> #include <Cnx/sync/UniqueLock.h> #include <Cnx/sync/SharedLock.h> #include "MyThing.h" void init_my_thing(void) { if(my_thing_mutex == nullptr) { my_thing_mutex = cnx_allocator_allocate_t(CnxSharedMutex, DEFAULT_ALLOCATOR); *my_thing_mutex = cnx_shared_mutex_new(); { // use a `CnxUniqueLock` to lock `my_thing_mutex`. // mark `lock` as `maybe_unused` so we don't get warnings about an unused variable __attr(maybe_unused) UniqueLock lock = cnx_unique_lock(*my_thing_mutex); my_very_important_thing = { // important intialization }; // `lock` automatically destroyed at scope end, releasing the lock on `my_thing_mutex` } } } void update_my_thing(u64 value) { __attr(maybe_unused) UniqueLock lock = cnx_unique_lock(*my_thing_mutex); my_very_important_thing.value = value; // `lock` automatically destroyed at scope end, releasing the lock on `my_thing_mutex` } u64 get_value_from_my_thing(CnxSharedLock lock) { // move lock into lock2 so that the mutex will be unlocked at scope exit __attr(maybe_unused) SharedLock lock2 = move(lock); let val = my_very_important_thing.value; return val; // `lock2` automatically destroyed at scope end, releasing the lock on `my_thing_mutex` } // do some compute intensive task... // update the value update_my_thing(new_value); SharedLock lock1 = cnx_shared_lock(*my_thing_mutex); my_val = get_value_from_my_thing(move(lock1)); // do something with my_val SharedLock lock2 = cnx_shared_lock(*my_thing_mutex); let_mut newval = get_value_from_my_thing(move(lock2)); while(newval == my_val) { cnx_this_thread_sleep_for(cnx_milliseconds(100)); SharedLock lock = cnx_shared_lock(*my_thing_mutex); newval = get_value_from_my_thing(move(lock)); } my_val = newval; // do something with new value