How to Use Mutex Lock in C

Jinku Hu Feb 02, 2024
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
Author: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

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