Mutex is a lock that could be used to prevent threads from reading from and/or writing to the variable that they share between each other. This could prevent the #202112061109 from happening since the program will be able to deny granting access of that variable to other threads when the mutex is currently locked by a thread. Such mechanism is great for code synchronisation.
In pthread, the creation of mutex could be done by declaring a global pthread_mutex_t
variable and initialise it by calling pthread_mutex_init
. To lock it, call pthread_mutex_lock
onto the mutex, and to unlock, call pthread_mutex_unlock
onto the mutex. At the end, we need to destroy the mutex from the program by calling pthread_mutex_destroy
.
pthread_mutex_t mutex;
// in the program
pthread_mutex_init(&mutex, NULL);
// at somewhere
pthread_mutex_lock(&mutex);
pthread_mutex_unlock(&mutex);
// at the end of the program
pthread_mutex_destroy(&mutex);
Trylock
Instead of using pthread_mutex_lock
, one could use pthread_mutex_trylock
to avoid threads from waiting. When pthread_mutex_trylock
is called, the thread will first try to obtain the mutex lock for itself. If that fail, the function will return non-zero value to indicate that the current mutex is busy, and the thread will execute its remaining content, of course without the content locked by the mutex. If it is a success, the function will return 0. Therefore, checking the return value of pthread_mutex_trylock
is necessary.
if (pthread_mutex_trylock(&mutex) == 0) {
// locked content
pthread_mutex_unlock(&mutex);
}
// remaining content
Recursive Lock
When the thread need to lock the mutex for multiple times, it is wise to use the recursive lock in order to prevent 202202191853. Since the default initialisation of mutex does not allow us to recursively lock it, we need to modify its attribute. To do that, we need to declare a pthread_mutexattr_t
and then initialise it by calling pthread_mutexattr_init
. Set the correct type by calling pthread_mutexattr_settype
. When calling on pthread_mutex_init
, pass it to its second parameter. Later on, clean it up using pthread_mutexattr_destroy
.
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mutex, &attr);
pthread_mutexattr_destroy(&attr);
Static Initialiser
Mutex could be statically initialised without using pthread_mutex_init
in order to acquire the necessary resources for itself. This could be a good shorthand for the user to keep this in their repertoire.
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
Although pthread_mutex_destroy
has become optional in this case, it is a good practice to keep it as it is much clearer where does the resources have been cleanup.
Fine Control Threads Execution’s Sequence
See 202112132216#