Synchronization and Race Conditions
Implement mutexes and semaphores to manage shared resources safely.
Synchronization and Race Conditions is a free C Academy lesson on CoddyKit. This is lesson 3 of 3. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C Academy learning path, and your progress syncs across the web and the CoddyKit app. The C Academy course includes 3 lessons in total.
Synchronization and Race Conditions
When multiple threads access shared resources, race conditions can occur, leading to unpredictable results.
In this lesson, you will learn:
- What race conditions are and how they occur.
- How to use mutexes to prevent race conditions.
- How semaphores help manage shared resources.

What is a Race Condition?
A race condition occurs when multiple threads access shared data simultaneously, leading to unpredictable behavior.
Example:
- Two threads try to update a global counter.
- The final value may be incorrect due to interference.
Example: Race Condition in Multithreading
This program demonstrates a race condition where multiple threads modify a shared variable.
#include <stdio.h>
#include <pthread.h>
int counter = 0;
void *incrementCounter(void *arg) {
for (int i = 0; i < 1000000; i++) {
counter++;
}
return NULL;
}
int main() {
pthread_t t1, t2;
pthread_create(&t1, NULL, incrementCounter, NULL);
pthread_create(&t2, NULL, incrementCounter, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
printf("Final counter value: %d\n", counter);
return 0;
}Preventing Race Conditions with Mutex
A mutex (mutual exclusion) ensures only one thread accesses a resource at a time.
Mutex functions:
pthread_mutex_init()- Initializes a mutex.pthread_mutex_lock()- Locks the mutex.pthread_mutex_unlock()- Unlocks the mutex.pthread_mutex_destroy()- Destroys the mutex.
Example: Using Mutex to Prevent Race Conditions
This program fixes the race condition by using a mutex to control access to the shared counter.
#include <stdio.h>
#include <pthread.h>
int counter = 0;
pthread_mutex_t lock;
void *incrementCounter(void *arg) {
for (int i = 0; i < 1000000; i++) {
pthread_mutex_lock(&lock);
counter++;
pthread_mutex_unlock(&lock);
}
return NULL;
}
int main() {
pthread_t t1, t2;
pthread_mutex_init(&lock, NULL);
pthread_create(&t1, NULL, incrementCounter, NULL);
pthread_create(&t2, NULL, incrementCounter, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_mutex_destroy(&lock);
printf("Final counter value: %d\n", counter);
return 0;
}What is a Semaphore?
A semaphore is a counter used to control access to resources.
Key functions:
sem_init()- Initializes a semaphore.sem_wait()- Decreases the semaphore value.sem_post()- Increases the semaphore value.sem_destroy()- Destroys the semaphore.
Example: Using Semaphores for Synchronization
This program uses a semaphore to manage access to a shared resource.
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
sem_t sem;
void *task(void *arg) {
sem_wait(&sem);
printf("Thread %d is executing\n", *(int *)arg);
sem_post(&sem);
return NULL;
}
int main() {
pthread_t t1, t2;
int id1 = 1, id2 = 2;
sem_init(&sem, 0, 1);
pthread_create(&t1, NULL, task, &id1);
pthread_create(&t2, NULL, task, &id2);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
sem_destroy(&sem);
return 0;
}Best Practices for Thread Synchronization
To avoid race conditions:
- Use mutexes to protect shared variables.
- Use semaphores for resource management.
- Minimize shared resource usage where possible.
Summary
In this lesson, you learned:
- What race conditions are and how they occur.
- How to use mutexes to prevent race conditions.
- How semaphores help manage access to shared resources.
This concludes the Multithreading and Concurrency section in C!

Learn C with an AI tutor — free
Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.
- Courses
- 39
- Lessons
- 144
Frequently Asked Questions
Is the “Synchronization and Race Conditions” lesson free?
Yes — the full text of “Synchronization and Race Conditions” is free to read here on the web. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C Academy course, upgrade to CoddyKit PRO. The C Academy course includes 3 lessons in total.
What will I learn in “Synchronization and Race Conditions”?
Implement mutexes and semaphores to manage shared resources safely. You practise C Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start C Academy?
No prior experience is required. C Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 3 of 3.
How long does the “Synchronization and Race Conditions” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this C Academy lesson?
Yes. Every C Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Introduction to Threads
- Creating and Managing Threads
- Synchronization and Race Conditions