Synchronization » CnxSharedMutex module

CnxSharedMutex provides several higher-level reader-writer mutex types comparable to those provided in C++'s <shared_mutex>, to make working with multi-threaded code simpler and easier.

A shared mutex is a reader-writer mutex that allows for different categories of locking, either exclusively, for writing/mutation, or non-exclusively/shared for reading. This can allow for significant throughput improvements in applications where many threads need to read the same data often, but only a comparatively small number of threads will ever try to mutate the data, by allowing the reading threads to share a lock on the mutex, while forcing a writing thread to gain an exclusive lock on the mutex to perform its mutation.

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 "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();

        cnx_shared_mutex_lock(my_thing_mutex);
        my_very_important_thing = {
        // important intialization
        };
        cnx_shared_mutex_unlock(my_thing_mutex);
    }
}

// only one thread at a time can `update_my_thing`, because it uses exclusive locking
void update_my_thing(u64 value) {
    cnx_shared_mutex_lock(my_thing_mutex);
    my_very_important_thing.value = value;
    cnx_shared_mutex_unlock(my_thing_mutex);
}

// any number of threads can `get_value_from_my_thing` without blocking eachother,
// because it uses shared locking.
u64 get_value_from_my_thing(void) {
    cnx_shared_mutex_lock_shared(my_thing_mutex);
    let val = my_very_important_thing.value;
    cnx_shared_mutex_unlock_shared(my_thing_mutex);
    return val;
}


// do some compute intensive task...
// update the value
update_my_thing(new_value);

my_val = get_value_from_my_thing();
// do something with my_val

let_mut newval = get_value_from_my_thing();
while(newval == my_val) {
    cnx_this_thread_sleep_for(cnx_milliseconds(100));
    newval = get_value_from_my_thing();
}

my_val = newval;
// do something with new value

Classes

struct CnxSharedMutex
CnxSharedMutex is the generic (it's not timed or recursive) reader-writer mutex provided by Cnx. It's directly comparable to C++'s std::shared_mutex and is suitable for any situation where a reader-writer mutex is necessary.
struct CnxSharedTimedMutex
CnxSharedTimedMutex is a higher-level reader-writer mutex type for use when timed backoff of mutex locking is required, and is directly comparable to C++'s std::shared_timed_mutex. It allows for specifying a timeout, which if reached will cause execution to stop attempting to acquire the lock and signal failure to the caller, instead of blocking indefinitely until the lock was successfully acquired like a tradition mutex. For example, if an algorithm needs reader-writer synchronization, but blocking for longer than X milliseconds when trying to acquire the lock would be problematic, a CnxSharedTimedMutex would be the appropriate mutex type to use.
struct CnxSharedMutexInterface

Functions

CnxSharedMutex cnx_shared_mutex_new(void)
Creates a new shared mutex.
void cnx_shared_mutex_lock(CnxSharedMutex*restrict mutex)
Unconditionally locks the mutex pointed to by mutex exclusively (aka for writing)
bool cnx_shared_mutex_try_lock(CnxSharedMutex*restrict mutex)
Attempts to lock the mutex pointed to by mutex exclusively (aka for writing)
void cnx_shared_mutex_lock_shared(CnxSharedMutex*restrict mutex)
Unconditionally locks the mutex pointed to by mutex non-exclusively (shared, aka for reading)
bool cnx_shared_mutex_try_lock_shared(CnxSharedMutex*restrict mutex)
Attempts to lock the mutex pointed to by mutex non-exclusively (shared, aka for reading)
void cnx_shared_mutex_unlock(CnxSharedMutex*restrict mutex)
Unlocks the exclusively locked mutex pointed to by mutex
void cnx_shared_mutex_unlock_shared(CnxSharedMutex*restrict mutex)
Unlocks the non-exclusively (aka shared) locked mutex pointed to by mutex
void cnx_shared_mutex_free(CnxSharedMutex*restrict mutex)
Destroys the mutex pointed to by mutex
CnxSharedTimedMutex cnx_shared_timed_mutex_new(void)
Creates a new shared timed mutex.
void cnx_shared_timed_mutex_lock(CnxSharedTimedMutex*restrict mutex)
Unconditionally locks the mutex pointed to by mutex exclusively (aka for writing)
bool cnx_shared_timed_mutex_try_lock(CnxSharedTimedMutex*restrict mutex)
Attempts to lock the mutex pointed to by mutex exclusively (aka for writing)
bool cnx_shared_timed_mutex_try_lock_for(CnxSharedTimedMutex*restrict mutex, CnxDuration duration)
Attempts to lock the mutex pointed to by mutex exclusively (aka for writing)
bool cnx_shared_timed_mutex_try_lock_until(CnxSharedTimedMutex*restrict mutex, CnxTimePoint stop_point)
Attempts to lock the mutex pointed to by mutex exclusively (aka for writing)
void cnx_shared_timed_mutex_lock_shared(CnxSharedTimedMutex*restrict mutex)
Unconditionally locks the mutex pointed to by mutex non-exclusively (shared, aka for reading)
bool cnx_shared_timed_mutex_try_lock_shared(CnxSharedTimedMutex*restrict mutex)
Attempts to lock the mutex pointed to by mutex non-exclusively (shared, aka for reading)
bool cnx_shared_timed_mutex_try_lock_shared_for(CnxSharedTimedMutex*restrict mutex, CnxDuration duration)
Attempts to lock the mutex pointed to by mutex non-exclusively (aka shared, for reading)
bool cnx_shared_timed_mutex_try_lock_shared_until(CnxSharedTimedMutex*restrict mutex, CnxTimePoint stop_point)
Attempts to lock the mutex pointed to by mutex non-exclusively (aka shared, for reading)
void cnx_shared_timed_mutex_unlock(CnxSharedTimedMutex*restrict mutex)
Unlocks the exclusively locked mutex pointed to by mutex
void cnx_shared_timed_mutex_unlock_shared(CnxSharedTimedMutex*restrict mutex)
Unlocks the non-exclusively (aka shared) locked mutex pointed to by mutex
void cnx_shared_timed_mutex_free(CnxSharedTimedMutex*restrict mutex)
Destroys the mutex pointed to by mutex

Function documentation

CnxSharedMutex cnx_shared_mutex_new(void)

Creates a new shared mutex.

Returns A CnxSharedMutex

void cnx_shared_mutex_lock(CnxSharedMutex*restrict mutex)

Unconditionally locks the mutex pointed to by mutex exclusively (aka for writing)

Parameters
mutex - The mutex to lock exclusively (aka for writing)

bool cnx_shared_mutex_try_lock(CnxSharedMutex*restrict mutex)

Attempts to lock the mutex pointed to by mutex exclusively (aka for writing)

Parameters
mutex - The mutex to lock exclusively (aka for writing)
Returns true if successful

If locking the mutex is successful, return true.

void cnx_shared_mutex_lock_shared(CnxSharedMutex*restrict mutex)

Unconditionally locks the mutex pointed to by mutex non-exclusively (shared, aka for reading)

Parameters
mutex - The mutex to lock non-exclusively (aka shared, for reading)

bool cnx_shared_mutex_try_lock_shared(CnxSharedMutex*restrict mutex)

Attempts to lock the mutex pointed to by mutex non-exclusively (shared, aka for reading)

Parameters
mutex - The mutex to lock non-exclusively (aka shared, for reading)
Returns true if successful

If locking the mutex is successful, return true.

void cnx_shared_mutex_unlock(CnxSharedMutex*restrict mutex)

Unlocks the exclusively locked mutex pointed to by mutex

Parameters
mutex - The mutex to unlock exclusively

void cnx_shared_mutex_unlock_shared(CnxSharedMutex*restrict mutex)

Unlocks the non-exclusively (aka shared) locked mutex pointed to by mutex

Parameters
mutex - The mutex to unlock non-exclusively

void cnx_shared_mutex_free(CnxSharedMutex*restrict mutex)

Destroys the mutex pointed to by mutex

Parameters
mutex - The mutex to free

CnxSharedTimedMutex cnx_shared_timed_mutex_new(void)

Creates a new shared timed mutex.

Returns A CnxSharedTimedMutex

void cnx_shared_timed_mutex_lock(CnxSharedTimedMutex*restrict mutex)

Unconditionally locks the mutex pointed to by mutex exclusively (aka for writing)

Parameters
mutex - The mutex to lock exclusively (aka for writing)

bool cnx_shared_timed_mutex_try_lock(CnxSharedTimedMutex*restrict mutex)

Attempts to lock the mutex pointed to by mutex exclusively (aka for writing)

Parameters
mutex - The mutex to lock exclusively (aka for writing)
Returns true if successful

If locking the mutex is successful, return true.

bool cnx_shared_timed_mutex_try_lock_for(CnxSharedTimedMutex*restrict mutex, CnxDuration duration)

Attempts to lock the mutex pointed to by mutex exclusively (aka for writing)

Parameters
mutex - The mutex to lock
duration - The amount to time spend trying to lock the mutex
Returns true if successful

Tries to lock the mutex until the amount of time specified by duration has passed. If locking is successful before duration has elapsed, returns true. Otherwise stops trying to acquire the lock and returns false.

bool cnx_shared_timed_mutex_try_lock_until(CnxSharedTimedMutex*restrict mutex, CnxTimePoint stop_point)

Attempts to lock the mutex pointed to by mutex exclusively (aka for writing)

Parameters
mutex - The mutex to lock
stop_point - The point in time at which to quit trying to lock the mutex
Returns true if successful

Tries to lock the mutex until the the point in time specified by stop_point. If locking is successful before stop_point has occurred, returns true. Otherwise stops trying to acquire the lock and returns false.

void cnx_shared_timed_mutex_lock_shared(CnxSharedTimedMutex*restrict mutex)

Unconditionally locks the mutex pointed to by mutex non-exclusively (shared, aka for reading)

Parameters
mutex - The mutex to lock non-exclusively (aka shared, for reading)

bool cnx_shared_timed_mutex_try_lock_shared(CnxSharedTimedMutex*restrict mutex)

Attempts to lock the mutex pointed to by mutex non-exclusively (shared, aka for reading)

Parameters
mutex - The mutex to lock non-exclusively (aka shared, for reading)
Returns true if successful

If locking the mutex is successful, return true.

bool cnx_shared_timed_mutex_try_lock_shared_for(CnxSharedTimedMutex*restrict mutex, CnxDuration duration)

Attempts to lock the mutex pointed to by mutex non-exclusively (aka shared, for reading)

Parameters
mutex - The mutex to lock
duration - The amount to time spend trying to lock the mutex
Returns true if successful

Tries to lock the mutex until the amount of time specified by duration has passed. If locking is successful before duration has elapsed, returns true. Otherwise stops trying to acquire the lock and returns false.

bool cnx_shared_timed_mutex_try_lock_shared_until(CnxSharedTimedMutex*restrict mutex, CnxTimePoint stop_point)

Attempts to lock the mutex pointed to by mutex non-exclusively (aka shared, for reading)

Parameters
mutex - The mutex to lock
stop_point - The point in time at which to quit trying to lock the mutex
Returns true if successful

Tries to lock the mutex until the the point in time specified by stop_point. If locking is successful before stop_point has occurred, returns true. Otherwise stops trying to acquire the lock and returns false.

void cnx_shared_timed_mutex_unlock(CnxSharedTimedMutex*restrict mutex)

Unlocks the exclusively locked mutex pointed to by mutex

Parameters
mutex - The mutex to unlock exclusively

void cnx_shared_timed_mutex_unlock_shared(CnxSharedTimedMutex*restrict mutex)

Unlocks the non-exclusively (aka shared) locked mutex pointed to by mutex

Parameters
mutex - The mutex to unlock non-exclusively

void cnx_shared_timed_mutex_free(CnxSharedTimedMutex*restrict mutex)

Destroys the mutex pointed to by mutex

Parameters
mutex - The mutex to free