Experiment 3
Safety and Liveness Properties
Name:- Sanket Pawar
URN:- 2023-B-15072004A
Exp-3 Demonstrate Safety and Liveness Properties in Mutual Exclusion
Lab Objective: Design and implement a program to demonstrate the safety and liveness
properties of mutual exclusion using the lock
Prerequisites: Students should have a basic understanding of C programming,
multithreading
concepts, and familiarity with mutex locks.
Outcome:
● Students will be able to understand concepts of safety and liveness in concurrent
programming.
● And apply knowledge of locks to implement mutual exclusion and enforce the safety of
property.
Instructions:
● Implement a program to demonstrate safety and liveness properties in mutual
exclusion.
● Set up a C programming environment with thread support for multithreading.
● Design and conduct various testing scenarios to observe the behavior of the program
under different conditions. Include cases that challenge both safety and liveness
properties.
● Familiarize students with debugging tools to identify and resolve issues related to
safety and liveness violations.
Ans:-
Lab Objective
The goal of this experiment is to:
Design and implement a program that demonstrates the safety and liveness properties of mutual
exclusion.
Use mutex locks to enforce safety in concurrent programming.
Test different conditions to analyze liveness issues, such as deadlock and starvation.
Prerequisites
Before starting this experiment, students should be familiar with:
1. C Programming Basics
2. Multithreading Concepts
o Creating and managing threads using pthread_create()
o Joining threads using pthread_join()
3. Mutex Locks in C
o pthread_mutex_t for synchronization of shared resources.
o Preventing race conditions by ensuring only one thread accesses critical sections at a time.
4. Safety and Liveness in Mutual Exclusion
o Safety Property: No two threads access the critical section at the same time.
o Liveness Property: Every thread eventually makes progress without indefinite blocking (no
deadlocks or starvation).
Expected Outcome
Students will understand the concepts of safety and liveness in concurrent programming.
They will learn how to use locks to ensure mutual exclusion and prevent race conditions.
They will experiment with various testing scenarios to analyze safety and liveness violations.
Step-by-Step Implementation
1. Implementing a Basic Mutual Exclusion Program
This program simulates multiple threads accessing a shared resource.
A mutex lock is used to enforce mutual exclusion.
We will test for safety and liveness by introducing delays and intentional blocking.
C Program: Demonstrating Safety and Liveness Using Mutex Locks
1️⃣ Ensuring Safety (No Two Threads Access the Critical Section Simultaneously)
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#define NUM_THREADS 3
#define ITERATIONS 5
pthread_mutex_t lock; // Mutex Lock
void *critical_section(void *arg) {
int thread_id = *(int *)arg;
for (int i = 0; i < ITERATIONS; i++) {
pthread_mutex_lock(&lock); // Lock to ensure mutual exclusion
printf("Thread %d is in the critical section (Iteration %d)\n", thread_id, i + 1);
sleep(1); // Simulate work being done in the critical section
printf("Thread %d is leaving the critical section (Iteration %d)\n", thread_id, i + 1);
pthread_mutex_unlock(&lock); // Unlock to allow other threads access
// Simulating non-critical work
usleep(500000); // Sleep for 500ms
return NULL;
int main() {
pthread_t threads[NUM_THREADS];
int thread_ids[NUM_THREADS];
pthread_mutex_init(&lock, NULL); // Initialize mutex lock
for (int i = 0; i < NUM_THREADS; i++) {
thread_ids[i] = i + 1;
pthread_create(&threads[i], NULL, critical_section, &thread_ids[i]);
for (int i = 0; i < NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
pthread_mutex_destroy(&lock); // Destroy mutex lock
printf("All threads completed execution.\n");
return 0;
Expected Output
Thread 1 is in the critical section (Iteration 1)
Thread 1 is leaving the critical section (Iteration 1)
Thread 2 is in the critical section (Iteration 1)
Thread 2 is leaving the critical section (Iteration 1)
Thread 3 is in the critical section (Iteration 1)
Thread 3 is leaving the critical section (Iteration 1)
...
This ensures safety, as only one thread is in the critical section at any given time.
2️⃣ Testing for Liveness Issues (Deadlock and Starvation)
Deadlock Scenario
A deadlock occurs when two or more threads are waiting for resources that will never be released.
Modified Code to Introduce Deadlock
void *deadlock_function(void *arg) {
int thread_id = *(int *)arg;
for (int i = 0; i < ITERATIONS; i++) {
printf("Thread %d is attempting to acquire the lock...\n", thread_id);
pthread_mutex_lock(&lock);
printf("Thread %d has acquired the lock (Iteration %d)\n", thread_id, i + 1);
sleep(2); // Simulating work in the critical section
// Inducing Deadlock: Forgetting to unlock
// pthread_mutex_unlock(&lock); // Uncomment this line to avoid deadlock
printf("Thread %d is leaving the critical section (Iteration %d)\n", thread_id, i +
1);
}
return NULL;
}
Scenario Analysis
If a thread locks but never unlocks, other threads cannot progress.
This creates a deadlock, violating liveness.
3️⃣ Fixing Deadlock Using Proper Unlocking
Always ensure the lock is released after the critical section.
Using pthread_mutex_unlock(&lock) prevents deadlock.
Testing Scenarios
Safety Property Testing
Run the first program and check no two threads enter the critical section simultaneously.
If two threads access the shared resource at the same time, it means mutual exclusion is violated.
Liveness Property Testing
Introduce intentional deadlocks and test if the program halts.
Implement timeouts to detect starvation (e.g., using pthread_cond_t).
Key Takeaways
1. Safety Property
o Ensures mutual exclusion: Only one thread enters the critical section at a time.
o Avoids race conditions, ensuring data consistency.
2. Liveness Property
o Ensures progress: Every thread gets a chance to execute.
o Avoids deadlock (threads stuck waiting for resources).
o Avoids starvation (one thread waiting indefinitely while others execute).
3. Deadlocks and Starvation
o Deadlock happens if a thread locks but never unlocks.
o Starvation happens if a thread never gets a chance to execute due to unfair scheduling.
o Both can be avoided using proper lock management.
Further Enhancements
Would you like me to extend this with:
Condition variables (pthread_cond_t) for better thread synchronization?
Semaphore-based synchronization (sem_t)?
Live debugging tips using GDB or Valgrind?