HomeAbout UsContact Us

C Program to implement custom mutex_lock() and mutex_unlock()

By Jithin Tom
Published in Embedded C/C++
September 07, 2025
1 min read
C Program to implement custom mutex_lock() and mutex_unlock()

Table Of Contents

01
C Program
02
Code Walkthrough
03
Frequently Asked Questions

This problem is a tricky question often asked during tech interviews. Here we need to create custom mutex_lock() and mutex_unlock() functions to mimic the actual behavior of mutex APIs. This program implements a mutex using atomic operations and busy waiting (spinning).

C Program

#include <stdio.h>
#include <stdatomic.h>
#include <pthread.h>
#include <stdint.h>
typedef struct {
atomic_flag flag;
} Mutex;
void Mutex_Init(Mutex* m) {
atomic_flag_clear(&m->flag); // initially unlocked
}
void Mutex_Lock(Mutex* m) {
while (atomic_flag_test_and_set(&m->flag)) {
// Busy wait (spinning)
}
}
void Mutex_Unlock(Mutex* m) {
atomic_flag_clear(&m->flag);
}
Mutex mylock;
void* worker(void* arg) {
Mutex_Lock(&mylock);
printf("Thread %lu entered critical section\n", (unsigned long)(uintptr_t)arg);
for (volatile int i = 0; i < 100000000; i++); // simulate work
printf("Thread %lu leaving critical section\n", (unsigned long)(uintptr_t)arg);
Mutex_Unlock(&mylock);
return NULL;
}
int main() {
pthread_t t1, t2;
Mutex_Init(&mylock);
pthread_create(&t1, NULL, worker, (void*)1);
pthread_create(&t2, NULL, worker, (void*)2);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
return 0;
}

Code Walkthrough

1. The Mutex Structure

typedef struct {
atomic_flag flag;
} Mutex;
  • atomic_flag is a special atomic boolean type.
  • It supports test-and-set operations that are thread-safe.
  • In simple terms: it can check if the lock is taken and set it in one atomic step, so no two threads can acquire it at the same time.

2. Initializing the Mutex

void Mutex_Init(Mutex* m) {
atomic_flag_clear(&m->flag); // initially unlocked
}
  • atomic_flag_clear sets the flag to 0 (unlocked).
  • At the start, the mutex is free, so the first thread can acquire it.

3. Locking the Mutex

void Mutex_Lock(Mutex* m) {
while (atomic_flag_test_and_set(&m->flag)) {
// Busy wait (spinning)
}
}
  • atomic_flag_test_and_set(&m->flag) does two things atomically:
    1. Checks the flag.
    2. Sets it to 1 (locked) if it was 0.
  • If the flag was already 1 → the function returns true → thread cannot enter.
  • The while loop keeps running → this is called busy waiting or spinning.
  • Once the flag becomes 0 (unlocked), the thread acquires the lock and exits the loop.

🔹 Analogy

  • Imagine a single key for a treasure box:
  • If someone has the key → you keep trying to take it repeatedly (spin).
  • When the key is free → you grab it immediately.

4. Unlocking the Mutex

void Mutex_Unlock(Mutex* m) {
atomic_flag_clear(&m->flag);
}
  • Clears the flag → sets it to 0 (unlocked).
  • Now another waiting thread can acquire the mutex.

5. Worker Function (Thread Task)

void* worker(void* arg) {
Mutex_Lock(&mylock);
printf("Thread %lu entered critical section\n", (unsigned long)(uintptr_t)arg);
for (volatile int i = 0; i < 100000000; i++); // simulate work
printf("Thread %lu leaving critical section\n", (unsigned long)(uintptr_t)arg);
Mutex_Unlock(&mylock);
return NULL;
}
  • Each thread locks the mutex before entering the critical section.
  • Only one thread can execute the critical section at a time.
  • After finishing, it unlocks the mutex.

6. Main Function

pthread_t t1, t2;
Mutex_Init(&mylock);
pthread_create(&t1, NULL, worker, (void*)1);
pthread_create(&t2, NULL, worker, (void*)2);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
  • Create 2 threads.
  • They both try to enter the critical section.
  • Only one thread can enter at a time because of the mutex.
  • Others spin in the loop until the lock is free.

7. Key Characteristics of This Method

FeatureDescription
TypeSpinlock mutex
Locking behaviorBusy wait (spins until lock is free)
CPU usageHigh if waiting, because thread keeps checking in a loop
Atomic operationatomic_flag_test_and_set ensures thread-safe locking
UnlockingClears the flag, allowing next thread to acquire

🔹 Visual Analogy

Thread 1: acquires lock -> executes critical section
Thread 2: sees lock taken -> keeps spinning (busy wait)
Thread 1: finishes -> unlocks
Thread 2: grabs lock -> executes critical section

Frequently Asked Questions

How does a custom spinlock mutex differ from an RTOS mutex?

A custom spinlock mutex continuously polls the lock variable in a busy-waiting loop, consuming 100% CPU cycles. An RTOS mutex blocks the calling task and yields CPU control to other tasks, making it much more efficient.

What is the role of atomic operations in mutex implementation?

Atomic operations like test-and-set guarantee that checking the state of a lock and acquiring it happens in a single, uninterruptible hardware transaction, preventing two threads from acquiring the lock simultaneously.

When is it appropriate to use a busy-waiting spinlock in an embedded system?

Spinlocks are only appropriate in multi-core systems where the resource is expected to be locked for a very short duration, or in bare-metal systems where no scheduler is available to block tasks.

Tags

embedded systemsc programmingrtosthreads

Share


Previous Article
C Program to implement modulo (%) operator using bitwise operators
Jithin Tom

Jithin Tom

A Closer Look at C/C++, RTOS, and Embedded Systems

Related Posts

Understanding the volatile Keyword in Embedded C
Understanding the volatile Keyword in Embedded C
May 08, 2026
3 min
© 2026, All Rights Reserved.
Powered By Netlyft

Quick Links

Advertise with usAbout UsContact Us

Social Media