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

OS-Module 3.1

Os
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views

OS-Module 3.1

Os
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 36

Module 3.

1
PROCESS SYNCHRONIZATION
Producer – Consumer Problem
 There is a Buffer with some number of slots.
 One item can be stored in each slot of the buffer.
 In and out are pointers to the buffer.
 Count is a variable which indicates the number of items in the buffer.
 Producer is the process which inserts items into the buffer.
 In points to the next free slot of buffer into which the producer process inserts the next item.
 In pointer is moved to the next position after inserting an item into the buffer.
 Count is incremented by 1 after inserting an item into the buffer.
 Consumer is the process which removes items from the buffer.
 Out points to the slot from which the consumer process removes the item.
 Out pointer is moved to the next position after removing an item from the buffer.
 Count is decremented by 1 after removing an item from the buffer.

2
Producer Process Consumer Process
The code of producer process is: The code of consumer process is:
while (true) while(true)
{ {
while (count == buffer_size) while (count == 0)
; ;
Buffer[in] = item; item = Buffer[out];
in = (in + 1) % buffer_size; out = (out+1) % buffer_size;
count = count + 1; count = count -1;
} }

3
Producer Process Consumer Process
The code of producer process is: The code of consumer process is:
while (true) while(true)
{ {
P1: while (count == buffer_size) C1: while (count == 0)
P2: ; C2: ;
P3: Buffer[in] = item; C3: item = Buffer[out];
P4: in = (in + 1) % buffer_size; C4: out = (out+1) % buffer_size;
P5: register1 = count; C5: register2 = count;
P6: register1 = register1 + 1; C6: register2 = register2 - 1;
P7: count = register1; C7: count = register2;
} }
Serial Execution of processes
Processes are executed one after another.
CPU is switched to next process only after completion of the currently running process.
N number of processes can be serially executed in N! number of ways.
For example, two processes p1 and p2 can be executed serially in two ways:
1) p1, p2 2) p2, p1
Three processes p1, p2 and p3 can be executed serially in six ways:
1) p1, p2, p3 2) p1, p3, p2 3) p2, p1, p3 4) p2, p3, p1 5) p3, p1, p2 6) p3, p2, p1

Concurrent Execution (or) Parallel Execution of processes


CPU can be switched to next process during execution of the current process.
The number of concurrent executions possible with n number of processes depends on the number of statements in each
process.

5
Independent processes

Processes running in the computer system are said to be independent processes if they are not exchanging or sharing any
data.

Cooperating processes

Processes running in the computer system are said to be cooperating processes if they are exchanging or sharing any data.

Correct output is generated when the independent processes are executed either serially or concurrently.

Correct output is generated when the cooperating processes are executed serially.

Concurrent execution of cooperating processes may generate wrong output.


One example concurrent execution of producer & consumer processes that leads to wrong result is:
P1, P2, P3, P4, P5, P6, C1, C2, C3, C4, C5, C6, P7, C7.

while (true) while(true)


{ {
P1: while (count == buffer_size) C1: while (count == 0)
P2: ; C2: ;
P3: Buffer[in] = item; C3: item = Buffer[out];
P4: in = (in + 1) % buffer_size; C4: out = (out+1) % buffer_size;
P5: register1 = count; C5: register2 = count;
P6: register1 = register1 + 1; C6: register2 = register2 - 1;
P7: count = register1; C7: count = register2;
} }

7
Another example concurrent execution of producer & consumer processes that leads to wrong result is:
P1, P2, P3, P4, P5, P6, C1, C2, C3, C4, C5, C6, C7, P7.

while (true) while(true)


{ {
P1: while (count == buffer_size) C1: while (count == 0)
P2: ; C2: ;
P3: Buffer[in] = item; C3: item = Buffer[out];
P4: in = (in + 1) % buffer_size; C4: out = (out+1) % buffer_size;
P5: register1 = count; C5: register2 = count;
P6: register1 = register1 + 1; C6: register2 = register2 - 1;
P7: count = register1; C7: count = register2;
} }

8
Race condition
Race condition is getting different outputs for different concurrent executions of cooperating processes.

Ex: What are the different values that A and B get after the execution of the processes P1, P2 concurrently?
Initial values of A and B are 6 and 4 respectively.

Process P1: Process P2:

I1: A=A-B; I11: A=A+1;


I2: B=B+A; I12: B=B-1;

9
Concurrent execution sequence1: I1, I2, I11, I12
A=6-4=2
B=4+2=6
A=2+1=3
B=6-1=5
A=3, B=5 Process P1: Process P2:

I1: A=A-B; I11: A=A+1;


I2: B=B+A; I12: B=B-1;
Concurrent execution sequence2: I1, I11, I12, I2
A=6-4=2
A=2+1=3
B=4-1=3
B=3+3=6
A=3, B=6
Concurrent execution sequence3: I1, I11, I2, I12
A=6-4=2
A=2+1=3
B=4+3=7
B=7-1=6
A=3, B=6 Process P1: Process P2:

I1: A=A-B; I11: A=A+1;


I2: B=B+A; I12: B=B-1;
Concurrent execution sequence4: I11, I12, I1, I2
A=6+1=7
B=4-1=3
A=7-3=4
B=3+4=7
A=4, B=7
Concurrent execution sequence5: I11, I1, I2, I12
A=6+1=7
A=7-4=3
B=4+3=7
B=7-1=6
A=3, B=6 Process P1: Process P2:

I1: A=A-B; I11: A=A+1;


I2: B=B+A; I12: B=B-1;
Concurrent execution sequence6: I11, I1, I12, I2
A=6+1=7
A=7-4=3
B=4-1=3
B=3+3=6
A=3, B=6
The different possible values that A and B can take are:
A=3, B=5
A=3, B=6
A=4, B=7
Critical Section of a process
Critical section of a process is the set of statements in the process which access and modify the shared data.

The critical section of producer process is:

register1 = count;
register1 = register1 + 1;
count = register1;

The critical section of consumer process is:

register2 = count;
register2 = register2 - 1;
count = register2;
Critical Section Problem
When two or more cooperating processes are executing concurrently, then at a time only one process should execute the
statements in its critical section.
(or)
When one process is already executing the statements in its critical section, no other process is allowed to execute the
statements in its critical section.
(or)
No two processes are allowed to execute the statements in their critical section at the same time.

When the execution of cooperating processes is restricted in this way then the correct output is generated even if the
cooperating processes are executed concurrently.

Each process must request permission to start the execution of statements in its critical section.

The section of code implementing this request is the entry section.

The critical section may be followed by an exit section which allows the other process to start the execution of
statements in its critical section.

The general structure of a process is shown in the following figure. 15


while (true)
{
.
.

Entry Section

Critical Section

Exit Section

.
.
}

Solutions for Critical Section Problem (or) Solutions for Implementing Mutual Exclusion

1. Peterson’s Solution or Software Solution


2. Hardware Solution
3. Semaphore Solution
4. Monitor Solution
A solution to the critical section problem must satisfy the following three conditions:
1) Mutual exclusion
2) Progress
3) Bounded waiting

Mutual Exclusion

No two processes should execute the statements in their critical section at the same time.

Progress

At any time, at least one process should be in the running state or active. No deadlock should occur.

Bounded waiting

All processes should be given equal chance to execute the statements in their critical sections.

17
Peterson’s Solution
It is applicable to two processes only.

Two variables are used


o int turn;

o boolean flag[2];

turn variable indicates whose turn it is to execute the statements in its critical section.

turn=1 - indicates that the 1st process (producer process) can execute the statements in its critical section.

turn=2 - indicates that the 2nd process (consumer process) can execute the statements in its critical section.

flag indicates whether a process is ready to execute the statements in its critical section.

flag[1]=true - indicates that the 1st process (producer process) is ready to execute the statements in its critical section.

flag[2]=true - indicates that the 2nd process (consumer process) is ready to execute the statements in its critical section.

Initially, flag[1] and flag[2] are set to false.

18
The following procedure is used to solve the critical section problem:

When the 1st process (producer process) wants to execute the statements in its critical section then the 1 st process (producer
process) sets flag[1] to true.

If the 2nd process (consumer process) is also ready to execute the statements in its critical section, then the 1 st process
(producer process) allows the 2nd process (consumer process) to execute the statements in its critical section by setting the
turn value to 2.

The 1st process (producer process) waits until the 2nd process (consumer process) completes the execution of statements in
its critical section.

Then the 1st process (producer process) starts executing the statements in its critical section.

The 1st process (producer process) sets flag[1] to false after completing the execution of statements in its critical section.

Same procedure is followed by the 2nd process (consumer process) when it wants to execute the statements in its critical
section.

19
Peterson’s solution to the critical section problem of producer-consumer is as follows:

Producer Process Consumer Process

while (true) while(true)


{ {
while (count == buffer_size) while (count == 0)
; ;
Buffer[in] = item; item = Buffer[out];
in = (in + 1) % buffer_size; out = (out+1) % buffer_size;

flag[1]=true; flag[2]=true;
Entry turn=2; Entry turn=1;
Section while(flag[2]==true && turn==2)
Section while(flag[1]==true && turn==1)
;
;
register1 = count;
register2 = count;
register1 = register1 + 1; Critical Section
register2 = register2 - 1; Critical Section
count = register1;
count = register2;
Exit flag[1]=false;
Section Exit flag[2]=false;
} Section
Hardware Solution

A variable named ‘lock’ is used.

boolean lock;

When a process wants to execute the statements in its critical section, the process checks the value of lock variable.

If the value of lock variable is true, then the process is not allowed to execute the statements in its critical section.

If the value of lock variable is false, then the process is allowed to execute the statements in its critical section.

Before executing the statements in the critical section, the process must set the value of lock variable to true.

After executing the statements in the critical section, the process must set the value of lock variable to false.

The structure of process is:

21
while (true)
{
.
.

Acquire lock;

Critical Section

Release lock;
.
.
}
Test_and_Set()

‘Test_and_Set’ is a hardware instruction which performs operations on the ‘lock’ variable to solve the critical section
problem.

It takes ‘lock’ variable as input and returns a boolean value.

The definition of Test_and_Set() is

boolean Test_and_Set(boolean lock)


{
boolean temp=lock;
lock=true;
return temp;
}

Test_and_Set() is an atomic instruction.

During the execution of Test_and_Set(), the CPU is not switched to any other process.

Initial value of ‘lock’ is false.


The solution to critical section problem of producer-consumer is

Producer Process Consumer Process

while (true) while(true)


{ {
while (count == buffer_size) while (count == 0)
;
;
Buffer[in] = item;
item = Buffer[out];
in = (in + 1) % buffer_size;
out = (out+1) % buffer_size;
Entry while(Test_and_Set(lock))
Section ; Entry while(Test_and_Set(lock))
Section ;
register1 = count;
register1 = register1 + 1; Critical Section register2 = count;
count = register1; register2 = register2 - 1; Critical Section
count = register2;
Exit lock=false;
Section Exit lock=false;
} Section
}
Swap()

‘Swap’ is another hardware instruction which is used to solve the critical section problem.

The definition of Swap() instruction is

void Swap(boolean lock, boolean key)


{
boolean temp=lock;
lock=key;
key=temp;
}

‘lock’ is a global variable.

‘key’ is a local variable.

Initial value of lock variable is false.

25
The solution to critical section problem of producer-consumer is

Producer Process Consumer Process

while (true) while(true)


{ {
while (count == buffer_size) while (count == 0)
; ;
Buffer[in] = item; item = Buffer[out];
in = (in + 1) % buffer_size; out = (out+1) % buffer_size;

Entry key1 = true; Entry key2 = true;


Section while(key1==true) while(key2==true)
swap(lock, key1); Section swap(lock, key2);

register1 = count; register2 = count;


register1 = register1 + 1; Critical Section register2 = register2 - 1; Critical Section
count = register1; count = register2;

Exit lock=false; Exit lock=false;


Section Section
} }
Semaphore Solution

Semaphore is an integer variable.

There are two types of semaphore:

1) Binary semaphore
2) Counting semaphore

Binary semaphore is used to solve the critical section problem.

Binary semaphore is also called as ‘mutex’ variable as binary semaphore is used to implement mutual exclusion.

Initial value of binary semaphore is 1.

Counting semaphore is used to provide synchronous access to a resource when the resource is requested by a number of
processes at a time.

Initial value of counting semaphore is equal to the number of instances of the resource.
A queue is associated with each semaphore variable.

Two atomic operations are defined on a semaphore variable:

1) wait()
2) signal()

The definition of wait() operation is:

wait(s)
{
s=s-1;
if(s<0)
{
Suspend the execution of the process which has invoked the wait() operation;
Insert that process in the queue associated with the semaphore variable s;
}
}
The definition of signal() operation is:

signal(s)
{
s=s+1;
if(s<=0)
{
remove a process from the queue associated with the semaphore variable s;
restart the execution of that removed process;
}
}

To solve the critical section problem, a process should invoke wait() operation on the semaphore variable before starting the
execution of statements in its critical section and should invoke signal() operation after executing the statements in its critical
section.

The structure of process is


.
.
wait(S);
Critical Section
signal(S);
.
.
The solution to critical section problem of producer-consumer is

Producer Process Consumer Process

while (true) while(true)


{ {
while (count == buffer_size) while (count == 0)
; ;
Buffer[in] = item; item = Buffer[out];
in = (in + 1) % buffer_size; out = (out+1) % buffer_size;

Entry wait(s); Entry wait(s);


Section Section
register1 = count; register2 = count;
register1 = register1 + 1; Critical Section register2 = register2 - 1; Critical Section
count = register1; count = register2;

Exit signal(s); Exit signal(s);


Section Section
} }
Classic problems of synchronization

1) Bounded buffer or producer-consumer problem


2) Readers-writers problem
3) Dining philosopher’s problem

Readers-Writers Problem

There is a database that can be shared by a number of concurrent processes.

Some processes named ‘Readers’ only read data from the database.

Other processes named ‘Writers’ write data to the database.

At a time, any number of Readers can read data from the database without any conflict.

But, when a Writer is writing data to the database then other Writers and Readers are not allowed to access the database.

Semaphore solution to the Readers-Writers Problem

The following semaphore variables are used:


semphore rw_mutex = 1;
semaphore mutex = 1;
int read_count = 0;

rw_mutex and mutex are binary semaphores.

read_count variable keeps track of how many Readers are currently reading from the database.

rw_mutex is used by both Readers and Writers to synchronously access the database.

mutex is used by Readers to synchronously access the read_count variable.

The code of a Writer process is:

while(true)
{
wait(rw_mutex);

Write data into the database;

signal(rw_mutex);
}
The code of a Reader process is:

while(true)
{
wait(mutex);
read_count = read_count + 1;
if(read_count == 1)
wait(rw_mutex);
signal(mutex);

Read data from the database;

wait(mutex);
read_count = read_count - 1;
if(read_count == 0)
signal(rw_mutex);
signal(mutex);
}
Dining Philosopher’s Problem

There are 5 philosophers.

A philosopher at any time is in either thinking or eating state.

The philosophers share a circular table surrounded by five chairs, each belonging to one philosopher.

In the center of the table is a bowl of rice, and the table is laid with five single chopsticks as shown in the diagram:
When a philosopher feels hungry then the philosopher tries to pick up the two chopsticks that are closest to him.

A philosopher may pick up only one chopstick at a time.

A philosopher cannot pick up a chopstick that is already in the hand of a neighbor.

When a hungry philosopher has both chopsticks at the same time, he eats without releasing the chopsticks.

When he is finished eating, he puts down both chopsticks and starts thinking again.

Semaphore solution to the Dining Philosopher’s problem

One simple solution is to represent each chopstick with a semaphore.

semaphore chopstick[5];

where all the elements of chopstick are initialized to 1.

A philosopher tries to grab a chopstick by executing a wait() operation on that semaphore.

A philosopher releases his chopsticks by executing the signal() operation on the appropriate semaphores.
The structure of philosopher i is:

while (true)
{
wait(chopstick[i]);
wait(chopstick[(i+1) % 5]);

Eat for a while;

signal(chopstick[i]);
signal(chopstick[(i+1) % 5]);

Think for a while;


}

You might also like