What is mutex?

A mutex is a type of lock used whenever multiple programs are using a shared resource to ensure that there isn't an invalid update of the shared resource.

Consider that we have two programs, namely A and B. Additionally, we have an integer variable x shared between both programs with two instructions that update the shared variable. In such a case, a mutex can ensure synchronization. In a CPU scheduling algorithm that simultaneously interrupts and runs processes that may result in incorrect values, we can ensure that both processes update the variable correctly.

Mutex operations

  • Lock: A program locks the mutex so that no other program can use the shared resources until the unlock function is called.

  • Unlock: Once a program finishes dealing with the shared resources, it will call the unlock function to release the lock so the other process can use it.

Why do we need mutex?

Let's say we have two processes A and B, and a variable i set to 0. Both processes need to call the operation i = i + 1, where i is a shared resource among both processes. Now, there is a possibility that we have an incorrect update of the value of i. Instead of i = 2, we may get i = 1. The diagram below explains this phenomenon.

Scheduling issue flowchart
Scheduling issue flowchart

We will solve the issue using a mutex. We will call the section which updates the variable i in both processes the critical section. A critical section is a piece of code that is shared among multiple processes. We will then implement a mutex around the critical section to ensure proper synchronization.

How To structure our code
How To structure our code

Every time a process tries to enter the critical section to execute the code written, it will check the status of the lock. If a process holds the lock, it means it is currently in the critical section. Hence, other processes can not enter and will have to wait for the initial process which holds the lock to finish its execution of the critical section and call unlock. Only then will another thread enter the critical section.

Below you can see a diagram that explains how a mutex is used which ensures proper synchronization of the shared variable i.

Scheduling with Mutex
Scheduling with Mutex

Properties of a mutex

  • It ensures mutual exclusion among multiple processes so that no two processes can access a critical section at the same time.

  • It safely executes multiple threads so that there is no data inconsistency between the threads in a multithreaded program.

  • It causes a process to be blocked/sleep if it tries to access a critical section for which the lock is already held by another process.

  • It ensures proper synchronization between threads to avoid conflicts.

Types of mutex

  1. Non-recursive mutex: A process can only lock and unlock this mutex once.

  2. Recursive mutex: A process can call the lock function and lock this mutex however many times it wants. It must also call the unlock the same number of times to free this mutex.

  3. Timed mutex: Allows a process to try to acquire a lock for a given period of time.

  4. Priority inheritance mutex: Ensures that the process with high priority gets hold of a mutex before the ones with low priority.

  5. Read-write mutex: Since there can be multiple reader and writer processes that wait on the mutex, this type of mutex ensures that only one writer program can hold the mutex at a time. Similarly, multiple reader processes can hold the mutex at once if there are no writer programs doing the same. This can be used in the infamous Producer-Consumer Problem.

Mutex implementation in C

To further understand how a mutex works, we will look at the C programs below, which show the working of the mutex from a coding point of view.

Multithreading without mutex

We see that a program with two threads, where each thread shares a variable counter and tries to update the variable without using a mutex, will yield incorrect results.

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
// declare the variable counter as a global variable
int counter;
// our thread function which will be ran by the threads
void* thread_function(void* arg){
// increment the value of the shared variable (counter) 1000000 for each thread
for(int i = 0; i < 1000000; i++){
counter = counter + 1;
}
return NULL;
}
int main(void){
pthread_t tid[2];
// create two threads to run the thread function which has the shared resource
pthread_create(&tid[0], NULL, &thread_function, NULL);
pthread_create(&tid[1], NULL, &thread_function, NULL);
// wait on both threads to finish execution
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
// Value Should Be 2000000
printf("Value Of Counter: %d\n", counter);
return 0;
}

Multithreading with mutex

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
// declare the variable counter as a global variable
int counter;
// initialize the mutex
pthread_mutex_t mutex;
// our thread function which will be ran by the threads
void* thread_function(void* arg){
// increment the value of the shared variable (counter) 100000 for each thread
for(int i = 0; i < 1000000; i++){
// lock the mutex
pthread_mutex_lock(&mutex);
// increment the shared variable
counter = counter + 1;
// unlock/release the mutex
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main(void){
pthread_t tid[2];
// create two threads to run the thread function which has the shared resource
pthread_create(&tid[0], NULL, &thread_function, NULL);
pthread_create(&tid[1], NULL, &thread_function, NULL);
// wait on both threads to finish execution
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
// Value Should Be 2000000
printf("Value Of Counter: %d\n", counter);
return 0;
}

To get the correct result in the program we saw earlier, we will include a mutex, lock it before we update the shared variable, and unlock it after the update. The result will show that the threads are properly synchronized with the help of a mutex.

Free Resources

Copyright ©2024 Educative, Inc. All rights reserved