How to Use Mutex Lock in C
This article will explain several methods of how to use mutex lock in C.
Use the pthread_mutex_t
Type and pthread_mutex_lock
Function to Guard the Critical Section of the Code
Threads share address spaces, which implies that modifications to the shared data like global variables must be synchronized; otherwise, there will be incorrect program behavior. Note that the following code creates 4 additional threads with the pthread_create
call and passes func3
as a starting point of their execution. func3
modifies the global variable shared
with one by one in a 10000 iteration for
loop. Thus, if the four threads increment the value of shared
by 10000 each, the program should output 40000.
If you execute the following code, the result will be some random integer, but not 40000. This behavior is classified generally as a race condition, implying that given threads access the shared variable without consulting each other i.e. synchronization. Namely, often when their execution of the loop interleaves, the inconsistency is reached in accesses and stores of the shared variable, and finally, an incorrect sum is yielded.
The code section where multiple threads modify the same object in the memory is called a critical section. Generally, the critical section should be protected with some type of lock that would force other threads to wait until the current thread finishes the execution and ensures that they all get the correct incremented value. Mutex is one of the lock types that can be utilized to guard the critical section like this for
loop in func3
.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif
int shared = 0;
void* func3(void* param) {
printf("Incrementing the shared variable...\n");
for (int i = 0; i < 10000; ++i) {
shared += 1;
}
return 0;
}
int main() {
pthread_t threads[NUM_THREADS];
for (int i = 0; i < NUM_THREADS; ++i) {
pthread_create(&threads[i], NULL, func3, NULL);
}
for (int i = 0; i < NUM_THREADS; ++i) {
pthread_join(threads[i], NULL);
}
printf("%d\n", shared);
exit(EXIT_SUCCESS);
}
Output:
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
30384
In this case, we will utilize the POSIX threads library and its built-in pthread_mutex_t
type. pthread_mutex_t
type variable is usually declared as static
storage duration. Mutex should be initialized only once before it’s used. When the mutex is declared as static
, one should use the PTHREAD_MUTEX_INITIALIZER
macro to initialize it. Once the mutex is initialized, threads can use pthread_mutex_lock
and pthread_mutex_unlock
functions correspondingly. pthread_mutex_lock
locks the mutex object passed as the only argument. If the mutex was already locked, the calling thread gets blocked until the mutex becomes available. pthread_mutex_unlock
should be called to unlock the mutex. If there are threads waiting on the same mutex, the scheduling policy determines which one gets the object lock. Finally, we call pthread_join
on each of the four threads and print the integer - shared
, which in this case should have the correct value stored.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif
int shared = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void* func3(void* param) {
pthread_mutex_lock(&mutex);
printf("Incrementing the shared variable...\n");
for (int i = 0; i < 10000; ++i) {
shared += 1;
}
pthread_mutex_unlock(&mutex);
return 0;
}
int main() {
pthread_t threads[NUM_THREADS];
for (int i = 0; i < NUM_THREADS; ++i) {
pthread_create(&threads[i], NULL, func3, NULL);
}
for (int i = 0; i < NUM_THREADS; ++i) {
pthread_join(threads[i], NULL);
}
printf("%d\n", shared);
exit(EXIT_SUCCESS);
}
Output:
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
40000
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook