0% found this document useful (0 votes)
3 views

OS LAB (Project)

The document discusses synchronization in operating systems, emphasizing its importance in coordinating threads and processes to prevent data inconsistency and race conditions. It covers basic concepts such as processes, threads, critical sections, and various synchronization problems like the producer-consumer and readers-writers problems. Additionally, it explains synchronization mechanisms including locks, semaphores, and their applications in real-world scenarios.

Uploaded by

M. Talha Malik
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

OS LAB (Project)

The document discusses synchronization in operating systems, emphasizing its importance in coordinating threads and processes to prevent data inconsistency and race conditions. It covers basic concepts such as processes, threads, critical sections, and various synchronization problems like the producer-consumer and readers-writers problems. Additionally, it explains synchronization mechanisms including locks, semaphores, and their applications in real-world scenarios.

Uploaded by

M. Talha Malik
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 35

OS LAB

SYNCHRONIZATION

PROJECT

UNIVERSITY OF MANAGEMENT AND TECHNOLOGY


1-27-2025
PROJECT
Group Members

MUHAMMAD ABUZAR F2022065260


MUHAMMAD SUHAIB F2022065279
ABDULLAH MUHAMMAD F2022065257

UNIVERSITY OF MANAGEMENT AND TECHNOLOGY


1-27-2025
Introduction

The word synchronization comes up with the meaning of which two or more things which run
or operates at the same time. Synchronization in OS is the coordination between the threads
and the processes to ensure the execution in the correct order which also ensures that which
critical part have to assign to which process to run the system smoothly and safely without
having the crash and also to avid the data inconsistency and race condition. It works in both
environment’s multithreading and also in the multi process. “In simple words if we talk about
the multiprocessors the process which run parallel in system but also, they have their different
memory and spaces if they crash, they the other processes are alive it does not damage it” on
the other hand “if we talk about the multithreading tasks which are run under the single
process it uses the one process memory if any thread crash it damages the other also”. In
synchronization the system executes the synchronization concurrently to ensure the critical
section of code to run it safely by keeping in view that there will be no race condition and
inconsistency.

Importance of OS synchronization:
 When the resources are share it maintains the data integrity.
 It ensures that there will be no race condition
 It supports and cooperate with inter process communication

Examples:
 In multithread web server thousands of client requests with handled simultaneously it
ensures the synchronization that data will be updated in cache consistently without
corruption.
 In banking system, it ensures the correct transaction details because at the same time
one or even multi transaction will do at the same time
 In real time synchronization occurs when multiple players play the game online at the
same time

“This essay explores the synchronization fundaments, its


common challenges, mechanisms its role in real modern world
and in future OS. “
Basic Concepts of Synchronization

First thing we know the concept of processes and threads in which the synchronization occurs

Processes:
A process is an independent task which has its own memory space whenever the process loads
into the memory the CPU assigns to the complete process.

Example:
We run two different applications one is the web browser and the other it the Microsoft word
both are different processes

Threads:
Threads are the smaller units with in the single process within the one memory space but it can
execute independently.

Example:
In web browser we run multiple threads in the form of we download from the web browser and
upload, search and the other stuff at the same time.

Shared resources:
The resources in which the processes and the threads want concurrently. It includes when any
process or threads wants to use the i/o devices, memory files etc.

Critical section:
It’s a part of the program in which the thread or the process wants to use but they can only be
executed by only one thread or the process at a time to prevent conflicts. The critical section
contains the shared variable that needs to be synchronized one time to maintain the
consistency of the data. When one process or thread using the critical section, it uses the
critical section and when it exits it generated the message so the other process or thread who
waiting for the critical section to use, they use it.

Code in example:
do {

entry section

critical section

exit section

reminder section

} while (true);

Race condition:
Race condition occurs inside the critical section. It occurs in the unpredictable condition when
the sequence or the timing of the threads not occur at the same time, we also say that it does
not update the latest thread.

Race condition may cause the data corruption on the unexpected behavior.

Example:
When two atm processes withdrawing the money at the same time even they were not
synchronized also they are from the same bank account they might to show the incorrect
balance.

 It leads to the data inconsistency.


 It also crashes the system for its unpredictable behavior.

Mutual exclusion:
It ensures that only one process or thread use or enters into the critical condition.

Example:
Lock in a file system when two processes writing concurrently on the same file. Basically, when
one thread who got the access first will lock the file and when it uses all its functionalities it
unlocks the file and run its further tasks so I that way one process and one thread can got
access at only one time.

 Its for avoiding the race condition and to ensure the data integrity.

Inter process communication:


The processes that coordinate and communicate their actions.

Examples:
It includes shared memory, message passing and pipes.

A parent process sends the data to the child process through the shared memory to share the
compute result.

Synchronization primitives:
Low level mechanisms and the programming languages implements synchronization.

Locks: it prevents access to a resource simultaneously.


Semaphores: a mechanism to control access to a finite number of resources.
Monitors: it constructs encapsulation in shared variables, condition variables, operations.
Synchronization Problems

Synchronization problem occurs when the multiple threads or the processes wants to access
the shared resource which we called the critical section at the same time concurrently. It will
lead to potential issues as well as the deadlocks occurs and starvation occurs. To prevent these
problems, we have the three classical synchronization problems.

 Producer consumer problem


 Readers writer problem
 Dinning philosophers problem

Producer consumer problem:


The producer consumer problem is the classical synchronization in which the two processes
describe one is the producer and the other is the consumer. The producer generates data and
put it in a buffer and the consumer removes the data from the buffer. The synchronization is
needed to ensure that because the buffer has the limited space.

 When the buffer is full the producer does not add the data.
 When the buffer is empty the consumer does not remove the data.

To control the access of the shared buffer the semaphore is used.

 Empty: how many empty slots are available in buffer.


 Full: how many filled slots are available for consumption.
 Mutex: while accessing the buffer we ensure the mutual exclusion.

Example:
A video streaming service one process uploads the video frames as he is producer and the other
displays any particular video that person is the consumer.

Code:
#include <iostream>
#include <thread>
#include <queue>
#include <semaphore> // C++20 semaphore support
#include <chrono>
using namespace std;

// Shared buffer and semaphores


queue<int> buffer;
const int bufferSize = 5; // Max size of buffer

semaphore emptySlots(bufferSize); // Initially, bufferSize empty slots


semaphore fullSlots(0); // Initially, no full slots
mutex bufferMutex; // Mutex for protecting shared buffer

void producer(int id) {


int item = 0; // Initial item value
while (true) {
// Produce an item (in this case, simply an incrementing integer)
this_thread::sleep_for(chrono::milliseconds(500)); // Simulate production delay
item++;

// Wait for an empty slot


emptySlots.acquire();

// Lock the buffer for mutual exclusion


lock_guard<mutex> lock(bufferMutex);
buffer.push(item);
cout << "Producer " << id << " produced item " << item << endl;

// Signal that a full slot is available


fullSlots.release();
}
}

void consumer(int id) {


while (true) {
// Wait for a full slot (an item to consume)
fullSlots.acquire();

// Lock the buffer for mutual exclusion


lock_guard<mutex> lock(bufferMutex);
int item = buffer.front();
buffer.pop();
cout << "Consumer " << id << " consumed item " << item << endl;
// Signal that an empty slot is available
emptySlots.release();

// Simulate consumption time


this_thread::sleep_for(chrono::milliseconds(1000)); // Simulate consumption delay
}
}

int main() {
// Create producer and consumer threads
thread producer1(producer, 1);
thread producer2(producer, 2);
thread consumer1(consumer, 1);
thread consumer2(consumer, 2);

// Join threads (though they will run indefinitely)


producer1.join();
producer2.join();
consumer1.join();
consumer2.join();

return 0;
}

Output:
Producer 1 produced item 1
Consumer 1 consumed item 1
Producer 2 produced item 2
Consumer 2 consumed item 2
Producer 1 produced item 3
Consumer 1 consumed item 3
Producer 2 produced item 4
Consumer 2 consumed item 4

Readers- writers problem:


The reader writer problem in operating system is to manage the access of the shared resource
its about when multiple users can access or reads the data at the same time without any issues
but the writer can write at a time then no one can read it while writing is happening.
 Readers: multiple readers can access the shared data simultaneously because they can
only read the data but they do not have the access to modify the data.
 Writers: only one writer can access the data at a time to ensure the data integrity as the
writers only modify the data only.

Example:
A file can be read by multiple users but it can only be edited by one writer.

Code:
#include <iostream>

#include <thread>

#include <mutex>

#include <vector>

#include <chrono>

std::mutex readLock;

std::mutex writeLock;

int readCount = 0;

void reader(int readerId) {

std::lock_guard<std::mutex> lock(readLock);

readCount++;

if (readCount == 1) {

writeLock.lock(); // First reader locks the writer.

// Reading section

std::cout << "Reader " << readerId << " is reading.\n";


std::this_thread::sleep_for(std::chrono::milliseconds(500));

std::lock_guard<std::mutex> lock(readLock);

readCount--;

if (readCount == 0) {

writeLock.unlock(); // Last reader unlocks the writer.

void writer(int writerId) {

writeLock.lock();

// Writing section

std::cout << "Writer " << writerId << " is writing.\n";

std::this_thread::sleep_for(std::chrono::milliseconds(500));

writeLock.unlock();

int main() {

std::vector<std::thread> threads;

// Create reader and writer threads.

for (int i = 0; i < 3; ++i) {

threads.push_back(std::thread(reader, i)); // Reader thread

threads.push_back(std::thread(writer, i)); // Writer thread

// Start all threads.


for (auto& t : threads) {

t.join();

return 0;

Output:
Reader 1 is reading.

Reader 2 is reading.

Reader 0 is reading.

Writer 1 is writing.

Writer 0 is writing.

Writer 2 is writing.

Dinning philosopher problem:


In this a group of philosopher sits in a dinning table and a fork is placed between the all the
philosopher and then one philosopher is going to use the both forks to eat but all the
philosopher will not grant the access of the forks at a time simultaneously if they do it will
prevent deadlock.
Example:
Multiple users trying to access the shared resource like printers simultaneously.

How it works:
process P[i]
while true do
{ THINK;
PICKUP(CHOPSTICK[i], CHOPSTICK[i+1 mod 5]);
EAT;
PUTDOWN(CHOPSTICK[i], CHOPSTICK[i+1 mod 5])
}

Var successful: boolean;


repeat
successful:= false;
while (not successful)

if both forks are available then


lift the forks one at a time;
successful:= true;

if successful = false
then
block(Pi);
{eat}
put down both forks;

if left neighbor is waiting for his right fork


then
activate (left neighbor);
if right neighbor is waiting for his left fork
then
activate( right neighbor);
{think}
forever

Synchronization Mechanisms

Locks:
Locks is the synchronization tool in which only one process access the shared resource and lock
that particular shared resource and then use its functionalities.

Mutex:
Mutex is also a type of lock in which it gathers the shared resource or the critical section and
then the other processes and the threads wait until it does not release it.

Example:
In back we have the multiple users but the mutex lock ensure that only one user modifiers the
balance to avoid the inconsistency.

Code:
#include <iostream>

#include <thread>

#include <mutex>

int sharedResource = 0;
std::mutex mtx;

void increment() {

mtx.lock();

sharedResource++;

std::cout << "Shared Resource: " << sharedResource << std::endl;

mtx.unlock();

int main() {

std::thread t1(increment);

std::thread t2(increment);

t1.join();

t2.join();

return 0;

Spin locks:
A spin lock is a type of lock which does not put the threads into waiting mode just like mutex it
checks again and again until the lock become available if it is available, it gathers that shared
resource.

Example:
We can take that example in which the system has high contention with the shared variable but
less with critical section.

Code:
#include <iostream>

#include <thread>

#include <atomic>
std::atomic_flag lock = ATOMIC_FLAG_INIT;

void criticalSection(int threadId) {

while (lock.test_and_set(std::memory_order_acquire)); // Spin until the lock is free

std::cout << "Thread " << threadId << " is in the critical section.\n";

lock.clear(std::memory_order_release); // Release the lock }

int main() {

std::thread t1(criticalSection, 1);

std::thread t2(criticalSection, 2);

t1.join();

t2.join();

return 0;

Recursive locks:
A recursive lock is the type of lock in which threads require the shared resource multiple times
without causing the dead locks.

Example:
A recursive lock ensures that there is no block itself either he is modifying a shared resource in
recursive function.

Code:
#include <iostream>

#include <thread>

#include <mutex>

std::recursive_mutex rmtx;

void recursiveFunction(int count) {

if (count <= 0) return;


rmtx.lock();

std::cout << "Recursion level: " << count << std::endl;

recursiveFunction(count - 1);

rmtx.unlock();

int main() {

std::thread t1(recursiveFunction, 3);

t1.join();

return 0;}

Semaphores

Semaphore is tool used in operating systems to help manage the access of different process to
a shared resources like memory or data without causing problems. Semaphores are used in
cases where we strictly need to limit the access of resources to only one process at a time. A
semaphore is basically lock-based mechanism designed for synchronization. Semaphores use a
counter to control the access of a process to several instances of one resource for eg. There can
be many instances of a CPU what it basically does is that it loops through the instances of a
resource and keeps on going until it finds a instances available or free. Semaphores are
designed for complex synchronization problems where there are multiple processes. It helps in
avoiding problems like race conditions by handling when and how process accesses the
resource.

Semaphores uses two main operations through which it handles process:

1. Wait() : The wait operation decrements the value of semaphore

wait(S) {

while (S <= 0)

; // busy wait

S--;

}
2. Signal() : The signal operation increments the value of semaphore

signal(S) {

S++;

When the semaphore value is zero it means that there is no resource currently available(all
resources are in use) so when a process calls the wait() it is blocked until another process does
signal(). So basically, the wait checks whether the semaphore >0 or not, if it is it decrements the
value of semaphore and continues the execution of the process

Similarly, the signal () operation is called by the process when it completes its execution and
leaves the resource free and increments signal ()

The initial value of a semaphore tells that how many total resources are available.

Two types of semaphores


1. Binary semaphores: the binary semaphore is used in cases where we are strictly
prohibited to allowing only one process to access a resource it is also known as a mutex
lock as it allows mutual exclusion. It has only two values 0 or 1 where 0 means that
resource is not available and 1 means that resource is available.
2. Counting semaphore: counting semaphores are normal semaphores which are used for
several instances of a resource.

The value of semaphore is equal to the total number of resources available.

Uses of semaphores
 Mutual exclusion: Semaphores makes sure that only one process gets access to a shared
resource.
 Resource management: Gives limited access to resources.
 Reader-Writer problem: Makes sure that multiple readers can access resources but no
writer unless there is no reader.
 Avoiding deadlocks: Prevents deadlocks by controlling resources access.

Advantages and Disadvantages


ADVANTAGES DISADVANTAGES
Helps avoid deadlocks by managing access of If not managed properly can lead to deadlock
resources
Prevents race conditions by making sure only Hard to debug and maintain as it has
one process accesses resource at once complex codes
Flexible Can cause performance issues

Producer-Consumer problem
Producer-Consumer problem is a synchronization problem which involves two threads:

1. Producer: Creates data and enters it into the buffer


2. Consumer: Takes data from the buffer

Now the main problem in this case is that we need to make sure:

 The producer doesn’t add data when buffer is full


 The consumer doesn’t remove data when buffer is empty

Code:
#include <iostream>
#include <thread>
#include <queue>
#include <semaphore>
#include <chrono>
#include <mutex>

using namespace std;


queue<int> buffer;
const int bufferSize = 5
semaphore emptySlots(bufferSize);
semaphore fullSlots(0);
mutex bufferMutex;
void producer(int id) {
int item = 0;
while (true) {
this_thread::sleep_for(chrono::milliseconds(500));
item++;
emptySlots.acquire();
{
lock_guard<mutex> lock(bufferMutex);
buffer.push(item);
cout << "Producer " << id << " produced item " << item << endl;
}
fullSlots.release();
}
}
void consumer(int id) {
while (true) {
fullSlots.acquire();
int item;
{
lock_guard<mutex> lock(bufferMutex);
item = buffer.front();
buffer.pop();
cout << "Consumer " << id << " consumed item " << item << endl;
}
emptySlots.release();
this_thread::sleep_for(chrono::milliseconds(1000));
}
}

int main() {
thread producer1(producer, 1);
thread producer2(producer, 2);
thread consumer1(consumer, 1);
thread consumer2(consumer, 2);
producer1.join();
producer2.join();
consumer1.join();
consumer2.join();
return 0;}

Monitors

Monitors are high level abstraction used in synchronization it is a safe way to manage shared
resources by encapsulating them in code which ensures mutual exclusion

Condition variables
A condition variable is a variable used to make the process wait for a certain condition before
proceeding it further implementation it has two mutex :

1. Wait
2. Signal

Use cases
Producer-Consumer problem
The notfull() and notempty() are condition variables in this case
Code:

#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <chrono>
class Monitor
{
private:
std::queue<int> buffer;
const int maxSize;
std::mutex mtx;
std::condition_variable notFull, notEmpty;

public:
Monitor(int size) : maxSize(size) {}

void produce(int item, int id)


{
std::unique_lock<std::mutex> lock(mtx);

// Wait until the buffer is not full


notFull.wait(lock, [this]() { return buffer.size() < maxSize; });

buffer.push(item);
std::cout << "Producer " << id << " produced item " << item << "\n";

// Notify that the buffer is not empty


notEmpty.notify_one();
}

void consume(int id)


{
std::unique_lock<std::mutex> lock(mtx);

// Wait until the buffer is not empty


notEmpty.wait(lock, [this]() { return !buffer.empty(); });

int item = buffer.front();


buffer.pop();
std::cout << "Consumer " << id << " consumed item " << item << "\n";

// Notify that the buffer is not full


notFull.notify_one();
}
};

void producer(Monitor& monitor, int id)


{
int item = 0;
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(500)); // Simulate production
time
monitor.produce(++item, id);
}
}

void consumer(Monitor& monitor, int id)


{
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // Simulate
consumption time
monitor.consume(id);
}
}

int main()
{
Monitor monitor(5); // Shared monitor with buffer size 5

// Create producer and consumer threads


std::thread producer1(producer, std::ref(monitor), 1);
std::thread producer2(producer, std::ref(monitor), 2);
std::thread consumer1(consumer, std::ref(monitor), 1);
std::thread consumer2(consumer, std::ref(monitor), 2);

// Join threads (though they will run indefinitely)


producer1.join();
producer2.join();
consumer1.join();
consumer2.join();

return 0;
}

Hardware Support for Synchronization

When multiple process needs to access shared resources, synchronization becomes crucial so
the hardware support helps provide mechanisms that make sure mutual exclusion and
communication

Test-and-set mechanism
In this operation it checks the value of memory location and if it is 1 then it allows the process
to occupy it and sets the value of the memory location to 1 showing that it has been locked and
once the process completes execution and leaves the memory location it returns back to 1

Code:
bool lock = false; // Initial state: lock is available
void acquire_lock() {
while(test_and_set(lock)) {
// Spin: keep trying to acquire the lock
}
}
void release_lock() {
lock = false; // Release the lock
}
Compare-and-swap mechanism
In this mechanism we compare a value of a memory location with expected value or a previous
value and if it matches, we change the value and in case it doesn’t match don’t change it and
try again

Code:
#include <iostream>
#include <atomic>
using namespace std;
bool compare_and_swap(atomic<int>& location, int expected_value, int new_value) {
int old_value = location.load(); // Get the current value

if (old_value == expected_value) {
location.store(new_value); // Update the value atomically
return true; // Successful swap
}
return false; // No swap, values didn't match
}

int main() {
atomic<int> shared_variable(10); // Shared variable initialized to 10

// Trying to swap the value 10 with 20


if (compare_and_swap(shared_variable, 10, 20)) {
cout << "Swap successful! New value: " << shared_variable.load() << endl;
} else {
cout << "Swap failed! Current value: " << shared_variable.load() << endl;
}
// Trying to swap the value 15 with 30 (this will fail)
if (compare_and_swap(shared_variable, 15, 30)) {
cout << "Swap successful! New value: " << shared_variable.load() << endl;
} else {
cout << "Swap failed! Current value: " << shared_variable.load() << endl;
}
return 0;
}

Deadlocks

What are deadlocks?


A deadlock is condition occurring in OS where process is not able to execute further because
each process is waiting for a resource which is held by another process this creates a circle in
which no process is able to proceed

Condition for deadlocks


1. Mutual Exclusion: Only one process at a time can access the shared resource
2. Hold and Wait: A process is waiting for a resource which is held by another process
3. No preemption: Resources cannot be forcibly snatched from any process until the
process leaves the resource itself
4. Circular wait: A circular chain is formed in which all processes are waiting for a resource
held by another process

If all these conditions exist then there is possibility of a deadlock

Prevention strategies
1.Prevention
To prevent going into a deadlock we need to make sure that we invalidate any one of the four
conditions mentioned above

2.Avoidance
It this strategy the system checks that if we grant a resource to a process will the system go into
deadlock

Banker’s Algorithm
This algorithm is the most commonly used algorithm which makes sure that the system
always stays in the safe state and the processes finish without deadlock

WORKING

At first processes declare the maximum number of resources they need then the system
checks that if the resources request is granted will all the process complete with
remaining resources

Resource allocation graph


The Resource allocation graph is graphical representation of the allocation of resources to
different processes

COMOPONENTS
 Process: Represented as circles

 Resources: Represented as rectangles with small dots


(representing instances)

 Edges:
o Request edge: Directed from process to resource
o Assignment edge: Directed from resource to process
The cycle in the graph tells that there is deadlock

Concurrency And Synchronization in Modern


Operating Systems

The modern Operating Systems make sure that there is synchronization and concurrency

USE OF SYNCHRONIZATION IN MODERN OS


1. Multithreading:
 In the modern OS threads of same process execute simultaneously
 Synchronization is ensured to prevent race conditions when shared resources
are accessed by processes
2. Process communication:
 Different mechanisms like pipes, message queues etc. are used
 Synchronization ensures IPC
3. Shared resources:
 Files, databases, I/O devices are shared between tasks
 Synchronization makes sure that there is not file mismanagement
Kernal-Level Synchronization mechanisms
1. Spinlocks
2. Semaphores
3. Mutexes
4. Read-write locks
5. Condition variables

Real-time operating systems (RTOS) and synchronization


1. Challenges
 RTOS are operating systems used in cases where time constraints are very
important, so synchronization just reduces the overhead
2. Flags
 Used for signaling tasks
3. Message queues
 Used for Inter-process communication

Performance Impacts of Synchronization

Synchronization is used to ensure coordination among different processes or threads in


concurrent programming.

Overheads of Locking
 Different locking mechanism (Mutex, Semaphore) have delays in them because
processes acquire and release shared memory.
 This can result in
 Increased latency due to lock acquisition and release.
 When thread waste time while waiting it effect the CPU efficiency.

Contention and Bottlenecks


 Contention occurs due to multiple threads competing for the same lock which cause
delays
 Bottlenecks happens when multiple threads acquire critical sections which slow down
the program.
 Programs with High concurrency or contention have these issues due to threads
spending more time in waiting.
Strategies to Optimize Synchronization
 Minimize Critical Section so threads spend less time waiting
 Independently locked parts which will reduces contention since threads can work
simultaneously on different parts of resource
 Restrict Multiple threads to write on shared resources, make shared resources as read
only resource
 Implement algorithm which reduces locking
 Reduced unnecessary synchronizations, such as when immutable objects are being
shared or when resources are thread local

Programming with Synchronization

Examples of synchronization in programming (e.g., in Java, C++).

APIs and libraries for synchronization.

Keywords of Synchronization in Programming

1. Java:
a. synchronized keyword
b. CyclicBarrier
c. ReentrantLock
d. CountDownLatch
e. CyclicBarrier
f. Semaphore
2. C++:
a. std::mutex,
b. std::lock_guard
c. std::condition_variable
d. std::unique_lock
e. std::atomic.

Example Code:
#include <iostream>
#include <thread>
#include <mutex>
using namespace std; // Simplifies code by removing the need for std:: prefix
mutex mtx; // Mutex for synchronization
int counter = 0;
void increment() {
for (int i = 0; i < 1000; ++i) {
lock_guard<mutex> lock(mtx); // Locks the mutex
counter++; } }
int main() {
thread t1(increment);
thread t2(increment);
t1.join();
t2.join();
cout << "Final Counter Value: " << counter << endl; // Prints final counter
return 0;}

Explanation of this code:


The above code uses mutex to ensure Thread synchronization, it also prevent race condition. In
this code there are 2 threads (T1 and T2) each incrementing the shared variable(counter) 1000
times through increment function without synchronization both threads will modify counter
concurrently which will result in race condition (in which modification from one thread
overwrites the modification of other thread)

To overcome this problem this code uses mutex (mtx) to protect the critical section (where
counter is being incremented), inside the function a lock_guard object locks the mutex for
each iteration of the loop which will control the access, updating of counter at a time, the
lock_guard releases the lock automatically when it goes out of the scope to avoid errors and
deadlock.
Emerging Trends in Synchronization

Non-blocking algorithms:
It allows the threads to work on its program or to access the critical section easily without being
blocked by other threads. it increases the performance and scalability.

Example:
In lock free link list, the multiple threads can add or remove nodes without using the locks it
also ensures that there is no bottleneck also ensures the progress.

Lock-free synchronization:
In lock free synchronization one thread can access finite number of steps.

Example:
If one thread is interrupted the other will also push or pop the threads l.

Wait-free synchronization:
Every thread is bounded to complete the number of threads with in the bounded numbers

Example:
Wait free is used in real time in counter system to ensure the thread safety.

Transactional memory:
Works just like the threads by dividing a large transactional into smaller parts or steps then the
transaction rolled back and retired.

Example:
STM allows developers or the group of operations to reduce the complexity and to manage the
locks.

Case Study

Synchronization Problem in E-Banking System


Problem Scenario:

In E-banking system it is very crucial to achieve synchronization for maintaining account


balance accuracy and avoiding data corruption/overriding. In case of failure in achieving
synchronization, race condition may occur leading to system failure specifically for cases in
which there are multiple users of the same account (Joint account, etc.)

Example:

Consider a scenario where:

1. When 2 users (processes) of a same account attempt to withdraw money concurrently.


2. Like if the initial account balance is 2002, and both users try to withdraw 1256 at same
time.

Failure Without Synchronization:

1. Process A (1st User) check the balance (2002) and find that the balance is greater than its
required account (1256)
2. At the same time process B (2nd user) also Checks the balance (2002) and finds it
sufficient for his need (1256)
3. Both make successful transaction at the same time leaving the balance of 746, although
the system should not allow these transactions

This problem is known as Race Condition which result in data inconsistency, which will lead to
financial loss of bank or can lead to severe consequences.

Synchronization Solution:

To avoid this problem, we should use methods of synchronization such as Semaphores or


Mutexes which ensure mutual exclusion while overwriting/modifying the account balance

Proposed Solution:

1. Use Mutex Lock to avoid Multiple threads (Users) to read and write critical sections
2. Make sure that only one thread at a time can access the Critical Section (Balance)

Improved Process:
 Process A (1st user) get the access to the Critical Section (Blanca) to read and write in it
and then complete it process
 After competition of Process A (1st User), Process B (2nd User) get the access of Critical
Section to do it task.

Challenges In Synchronization

1.Scalilbilty in multi core systems


Contention of shared resources
 Multiple processes trying to access a shared resource can lead to contention
which will ultimately lead to bottleneck.

Coherence
 Trying to keep data consistency among different caches can be tricky which can
lead to slowing down the overall process

Delays due to locks


 When we use different locking mechanisms which introduce significant delays in
the system ultimately increasing work load to multiple resources

2. Synchronization in Distributed Systems


Latency and Network Delays
 Unnecessary communication between computers in distributed systems causes
delays

Clock Synchronization
 Maintain same clock among different computers Is difficult to achieve due to
network issues or lags

Fault Tolerance
 Disconnecting from the network makes it hard for systems to maintain
synchronization

Deadlocks
 Hard to maintain synchronization because different parts of the system are stuck
waiting for each other to complete

Conclusion

In modern operating system the data integrity and reliability are important for the essential
synchronization. Without proper synchronization the system will crash it leads to data
corruption and also gives the unpredictable results without using the proper synchronization.
Tools like mutex (it is basically the flag which indicates the lock system into the any thread or
the process as no one will access it until it releases it) and semaphores (it checks the number of
resources that how many resources are available inside the system) are the advanced tools of
synchronization. The transactional memory and the conditional variables reboot the
synchronization challenges. By addressing the issues like deadlocks, race conditions and other
that ensures the safe parallel execution of all the multithreads and multiprocessor
environments. The case study will highlight how the synchronization works in the real-world
applications these principles can solve the real- world problems. It also ensures the seamless
results in critical applications like video streaming. As technology changes now the lock free
algorithms and wait-free algorithms are now used for the efficient synchronization it will
continue a vital role in programming as well as the operating system.

References
CHAT GPT 4 PRO, GEEKS FOR GEEKS, W3SCHOOLS, OS-BOOK.COM, YOUTUBE, COPILOT, WIKIPEDIA

You might also like