Sei sulla pagina 1di 70

Process Synchronization

Operating Systems - 1

Background
Concurrent access to shared data may result
in data inconsistency.
Maintaining data consistency requires
mechanisms to ensure the orderly execution
of cooperating processes.

Operating Systems - 1

Bounded-Buffer

Shared data

#define BUFFER_SIZE 10
typedef struct {
...
} item;
item buffer[BUFFER_SIZE];
int in = 0;
int out = 0;
int counter = 0;
Producer process

Consumer process

item nextProduced;

item nextConsumed;

while (1) {
while (counter == BUFFER_SIZE)
; /* do nothing */
buffer[in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
counter++;

while (1) {
while (counter == 0)
; /* do nothing */
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
counter--;
}

Operating Systems - 1

Bounded Buffer
The statements
counter++;
counter--;
must be performed atomically.
Atomic operation means an operation that
completes in its entirety without interruption.

Operating Systems - 1

Bounded Buffer
The statement counter++ may be implemented in
machine language as:
register1 = counter
register1 = register1 + 1
counter = register1
The statement counter-- may be implemented as:
register2 = counter
register2 = register2 1
counter = register2
Operating Systems - 1

Bounded Buffer
If both the producer and consumer attempt to
update the buffer concurrently, the assembly
language statements may get interleaved.
Interleaving depends upon how the producer
and consumer processes are scheduled.

Operating Systems - 1

Bounded Buffer

Assume counter is initially 5. One interleaving of


statements is:

producer: register1 = counter (register1 = 5)


producer: register1 = register1 + 1 (register1 = 6)
consumer: register2 = counter (register2 = 5)
consumer: register2 = register2 1 (register2 = 4)
producer: counter = register1 (counter = 6)
consumer: counter = register2 (counter = 4)
The value of count may be either 4 or 6, where
the correct result should be 5.
Operating Systems - 1

Race Condition
Race condition:
The situation where several processes access
and manipulate shared data concurrently. The
final value of the shared data depends upon which
process finishes last.

To prevent race conditions, concurrent


processes must be synchronized.
Operating Systems - 1

The Critical-Section Problem


n processes all competing to use some
shared data
Critical section, in which the shared data
is accessed.
Mutual Exclusion
ensure that when one process is executing in
its critical section, no other process is
allowed to execute in its critical section.

Operating Systems - 1

Operating Systems - 1

Mutual Exclusion

Operating Systems - 1

Solution to Critical-Section Problem must satisfy

1. Mutual Exclusion
No two processes may be simultaneously inside
their critical regions

2. Progress
No process running outside the critical region may block
other process,
Only those processes that are not executing in their
remainder section can participate in deciding which will
enter its critical section next, within a finite time.

3. Bounded Waiting
No process should have to wait forever to enter its
critical region.

No assumptions may be made about speeds or the


number of CPUs.
Operating Systems - 1

Solution for mutual exclusion


Disabling the interrupts
The user process can disable the clock interrupts
once it has entered the critical region.

Lock Variables
A variable with a value 0 for allowing the
processes to enter the critical section and 1 for
restricting it is used.
Operating Systems - 1

Initial Attempts to Solve Problem


Only 2 processes, P0 and P1
General structure of process Pi (other process Pj)
do {
entry section
critical section
exit section
remainder section
} while (1);
Processes may share some common variables to
synchronize their actions.
Operating Systems - 1

Algorithm 1 (Strict Alternation)

Operating Systems - 1

Strict Alternation

Mutual Exclusion is solved but progress is not


maintained
Operating Systems - 1

Algorithm 2

Shared variables
boolean flag[2];
initially flag [0] = flag [1] = false.
flag [0] = true P0 ready to enter its critical section
Process P0
do {
flag[0] = true;
while (flag[1]) ;
critical section
flag [0] = false;
remainder section
} while (1);

Process P1
do {
flag[1] = true;
while (flag[0]) ;
critical section
flag [1] = false;
remainder section
} while (1);

The problem lies when both the flags of the process are true at the same
instant.

Operating Systems - 1

Demerits of the previous algorithm


Process- A
FLAG_ A = True

Testing Condition

Process- B
FLAG_B = True

Testing Condition

! Flag_B

! Flag_A

Critical Section

Mutual Exclusion is solved, but still non progression prevails

Operating Systems - 1

Algorithms discussed earlier


Software Solutions Algorithm
Lock variable with a single value for all the process
Lock variable with two values for two different
process. (alternation).

Hardware Solutions
Disabling the interrupts

Operating Systems - 1

Petersons Solution
Restricted to two process
Alternate execution between critical section
and remainder section
Shared data:
int turn; //whose turn to enter critical section
boolean flag[2]; //true means process ready to
enter CS
Operating Systems - 1

Petersons algorithm
Combined shared variables of algorithms 1 (alternation) and 2.
Process Pi
do {
flag [i]:= true;
turn = j;
while (flag [j] && turn == j) ;
critical section
flag [i] = false;
remainder section
} while (1);
Meets all three requirements; solves the critical-section problem for
two processes.

Operating Systems - 1

Petersons Algorithm Global View


Process P0:
Do {
flag[0]:=true;
// 0 wants in

turn:= 1;

Process P1:
Do {
flag[1]:=true;
// 1 wants in

turn:=0;

// 0 gives a chance to 1

// 1 gives a chance to 0

while
(flag[1]&&turn==1);
CS
flag[0]:=false;

while
(flag[0]&&turn==0);
CS
flag[1]:=false;

// 0 no longer wants in

// 1 no longer wants in

RS
While (1);

RS
While (1);

There could be a situation that both flag [0] and flag[1] are true.
But even in that case the turn can have only one value.

Operating Systems - 1

Progression property in Petersons


problem
Process- A
FLAG_ A = True

Process- B
FLAG_B = True

Turn = B

Turn = A
Testing Condition

Testing Condition
! (Flag_B and Turn== B)

FLAG_ A = false

Critical Section

progression property satisfies

Operating Systems - 1

! (Flag_A and Turn= =A)

Handling of critical sections in OS


Two general approaches are used to handle critical
sections in operating systems:
preemptive kernels and
nonpreemptive kernels.
A preemptive kernel allows a process to be
preempted while it is running in kernel mode.
A non-preemptive kernel does not allow a process
running in kernel mode to be preempted; a kernelmode process will run until it exits kernel mode,
blocks, or voluntarily yields control of the CPU.
Operating Systems - 1

Preemptive kernel are difficult to implement


in SMP
Still we prefer them. Why?
Real time OS

Operating Systems - 1

Question on Petersons algorithm


Does Petersons solution to the mutual
exclusion problem work when process
scheduling is preemptive ( not in the critical
region )? How about when it is nonpreemptive?

Operating Systems - 1

What about Process Failures?


If all 3 criteria (ME, progress, bounded waiting)
are satisfied, then a valid solution will provide
robustness against failure of a process in its
remainder section (RS)
since failure in RS is just like having an infinitely long
RS

However, no valid solution can provide


robustness against a process failing in its critical
section (CS)
A process Pi that fails in its CS does not signal that fact
to other processes: for them Pi is still in its CS
Operating Systems - 1

N-process Solution: Bakery Algorithm


Before entering their CS, each Pi receives a number.
Holder of smallest number enter CS (like in bakeries,
ice-cream stores...)
When Pi and Pj receives same number:
if i<j then Pi is served first, else Pj is served first

Pi resets its number to 0 in the exit section


The numbering scheme always generates numbers in
increasing order of enumeration; i.e., 1,2,3,3,3,3,4,5...
Notation:
(a,b) < (c,d) if a < c or if a == c and b < d
max(a0,...ak) is a number b such that
b >= ai for i=0,..k

Operating Systems - 1

The Bakery algorithm (cont.)


Shared data:
choosing: array[0..n-1] of boolean;
initialized to false- to maintain the status of the process

number: array[0..n-1] of integer;


initialized to 0

Correctness relies on the following fact:


If Pi is in CS and Pk[k!=i] has already chosen its
number[k]!= 0, then (number[i],i) < (number[k],k)

Operating Systems - 1

Bakery algorithm for n processes


R
ProcessPi
do {
choosing[i ] true;
T
D number[i ] max(number[0], number[1], number[n 1]) 1;
choosing[i ] false;
for( j 0; j n; j ) {
T-D while(choosing[ j ]);
while((number[ j ]! 0) & &((number[ j ], j ) (number[i ], i )));
}
C
critical section
number[i ] 0;
E
remainder section
} while(1)

Operating Systems - 1

Structure of the algorithm


R code prior to using Bakery algorithm
T creating of a ticket and awaiting for permission to
enter critical section
D creation of a number (first part of a ticket)
T-D awaiting for the permission to enter critical section

C critical section itself


E code executed upon exit from critical section

Operating Systems - 1

Working of the bakery algorithm- For


Pb number
Choosing a number
Pa

false

Pb

True false
false

1 0 0

Pc

True false
false

Pd

True false
false

Pb will compare its status with Pa,Pb, Pc and Pd


The Pb need not compare its status with another process which has not chosen a non zerovalue
The process has to wait if the compared process is currently choosing the number
If the number of the process compared is < Pb, then Pb has to wait till the other process
completes the critical section.

Operating Systems - 1

Working of the bakery algorithm- For


Pc number
Choosing a number
Pa

false

Pb

false

1 0

Pc

false

2 0

Pd

True false
false

Pc will compare its status with Pa,Pb and Pd


The Pc need not compare its status with another process which has not chosen a non zerovalue
The process has to wait if the compared process is currently choosing the number
If the number of the process compared is < Pc, then Pc has to wait till the other process
completes the critical section.

Operating Systems - 1

Working of the bakery algorithm- same number


Choosing a number number
Pa

false
0

PID
101

Pb

false

Pc

false

103

Pd

false

104

102

Pc will compare its status with Pa,Pb and Pd


If two process has the chosen the same number then their PIds should be compared

Operating Systems - 1

Drawbacks of Software Solutions


Processes that are requesting to enter in their
critical section are busy waiting (consuming
processor time needlessly)
If Critical Sections are long, it would be more
efficient to block processes that are waiting...

Operating Systems - 1

Hardware Solutions: Interrupt


Disabling
On a uniprocessor: mutual exclusion
is preserved, prune to hold indefinite
control of CPU
On a multiprocessor: mutual
exclusion is not preserved
CS is now atomic but not
mutually exclusive
Message passing may be delayed

Generally not an acceptable


solution

Operating Systems - 1

Process Pi:
repeat
disable interrupts
critical section
enable interrupts
remainder section
forever

Synchronization Hardware
Many systems provide hardware support for
critical section code
Uniprocessors could disable interrupts
Currently running code would execute without
preemption
Generally too inefficient on multiprocessor systems
Operating systems using this not broadly scalable

Modern machines provide


hardware instructions
Atomic = non-interruptable

special

Either test memory word and set value


or swap contents of two memory words
Operating Systems - 1

atomic

TestAndSet Instruction
Definition:
boolean TestAndSet (boolean *target)
{
boolean rv = *target;
*target = TRUE;
return rv;
}

Operating Systems - 1

Mutual exclusion impl. with TestAndSet


Shared boolean variable lock, initialized to FALSE
Solution:
do {
while ( TestAndSet (&lock )); // do nothing
// critical section
lock = FALSE;
//

remainder section

} while (TRUE);
Operating Systems - 1

Bounded-waiting Mutual Exclusion with TestandSet()


do {
waiting[i] = TRUE;
key = TRUE;
while (waiting[i] && key)
key = TestAndSet(&lock);
waiting[i] = FALSE;
// critical section
j = (i + 1) % n;
while ((j != i) && !waiting[j])
j = (j + 1) % n;
if (j == i)
lock = FALSE;
else
waiting[j] = FALSE;
// remainder section
} while (TRUE);

Operating Systems - 1

Solution using Swap


Shared/Global Boolean variable lock initialized to FALSE;
Each process has a local Boolean variable key
Solution:
do {
key = TRUE;
while ( key == TRUE)
Swap (&lock, &key );
// critical section
lock = FALSE;
// remainder section
} while (TRUE);

Operating Systems - 1

void Swap (boolean *a, boolean *b)


{
boolean temp = *a;
*a = *b;
*b = temp:
}

Semaphore

Operating Systems - 1

Semaphore Principle
Two or more processes can cooperate by means
of simple signals, such that a process can be
forced to stop at a specified place until it has
received a specific signal.

For signaling, special variables called semaphores


are used.
Semaphore is a synchronization tool that does
not require busy waiting.
Operating Systems - 1

Semaphore Variable
Semaphore S is an integer variable
Operations possible on the semaphore variable are
may be initialized to a nonnegative value.
The wait operation decrements the semaphore value.
The signal operation increments the value of the semaphore.

Wait and signal are atomic operations


Types of semaphore
General Semaphore
It can take any value

Binary semaphore
It can take only 0 and 1.

Operating Systems - 1

Semaphores
Semaphore is a type of generalized lock

Defined by Dijkstra in the last 60s


Main synchronization primitives used in UNIX
Consist of a positive integer value
Two operations
P(): an atomic operation that waits for semaphore to become
positive, then decrement it by 1
V(): an atomic operation that increments semaphore by 1 and
wakes up a waiting thread at P(), if any.

Operating Systems - 1

Operations on Semaphore variable


Struct semaphore
{
int count;
queueType queue;

}
wait (S)
{
while (S<=0)
; // no -op
S--;

}
Operating Systems - 1

signal (S)
{
S++;
}

Weak and Strong semaphore


The semaphore that do not specify the order
in which processes are removed from the
queue is a weak semaphore.
The semaphore that specifies the order in
which processes are removed from the queue
is a strong semaphore. FIFO is followed as it is
a queue.

Operating Systems - 1

Revisit of wait and signal


To transmit a signal
Signal ( ) is used

To receive a signal
wait ( ) is used

Operating Systems - 1

Semaphore as General Synchronization


Tool

Counting semaphore integer value can range over an unrestricted


domain
Binary semaphore integer value can range only between 0 and 1; can be
simpler to implement
Also known as mutex locks
Can implement a counting semaphore S as a binary semaphore
Provides mutual exclusion
Semaphore mutex; // initialized to 1
do {
wait (mutex);
// Critical Section
signal (mutex);
// remainder section
} while (TRUE);

Operating Systems - 1

Operating Systems - 1

Semaphore Implementation
Must guarantee that no two processes can execute
wait () and signal () on the same semaphore at the
same time
The main disadvantage of the semaphore definition
given here is that it requires Busy Waiting (SPIN
LOCK).
While a process is in its critical section, any other
process that tries to enter its critical section must
loop continuously in the entry code.
Note that applications may spend lots of time in
critical sections and therefore this is not a good
solution.
Operating Systems - 1

Semaphore Implementation with no Busy


waiting
With each semaphore there is an associated waiting queue
Each entry in a waiting queue has two data items:
value (of type integer)
pointer to next record in the list
Two operations:
block place the process invoking the operation on the appropriate
waiting queue
wakeup remove one of processes in the waiting queue and place it in
the ready queue
Thus, implementation becomes the critical section problem where the wait
and signal code are placed in the critical section
Could now have busy waiting (SPIN LOCK) in critical section
implementation
But implementation code is short
Little busy waiting if critical section rarely occupied

Operating Systems - 1

Semaphore Implementation with no Busy waiting


(Cont.)

Implementation of wait:
wait(semaphore *S) {
S->value--;
if (S->value < 0) {
add this process to S->list;
block();
}
}
Implementation of signal:

signal(semaphore *S) {
S->value++;
if (S->value <= 0) {
remove a process P from S->list;
wakeup(P);
}
}

Operating Systems - 1

Deadlock and Starvation

Deadlock two or more processes are waiting indefinitely


for an event that can be caused by only one of the waiting
processes
Let S and Q be two semaphores initialized to 1
P0
P1
wait (S);
wait (Q);
.
.
.
signal (S);
signal (Q);

Starvation indefinite blocking

wait (Q);
wait (S);

.
.
.
signal (Q);
signal (S);

A process may never be removed from the semaphore queue in


which it is suspended (LIFO queue implementation)

Priority Inversion Scheduling problem when lowerpriority process holds a lock needed by higher-priority
process
Solved via priority-inheritance protocol

Operating Systems - 1

Classical Problems of Synchronization


Classical problems used to test newlyproposed synchronization schemes
Bounded-Buffer Problem
Readers and Writers Problem
Dining-Philosophers Problem

Operating Systems - 1

Bounded-Buffer Problem
N buffers, each can hold one item

Semaphore mutex initialized to the value 1


Semaphore full initialized to the value 0
Semaphore empty initialized to the value N

Operating Systems - 1

Bounded Buffer Problem (Cont.)


The structure of the producer process

mutex=1
empty=n
full=0

Operating Systems - 1

Bounded Buffer Problem (Cont.)

Producer
do {
//

Consumer process
do {

produce an item in nextp


wait (empty);
wait (mutex);

// add the item to the buffer


signal (mutex);
signal (full);

} while (TRUE);

Operating Systems - 1

wait (full);
wait (mutex);
// remove an item from
// buffer to nextc
signal (mutex);
signal (empty);
// consume the item in
// nextc
} while (TRUE);

Bounded Buffer Problem (Cont.)

Semaphore library and its system call


sem_init(),
sem_destroy(),
sem_post(),
sem_wait(),
sem_overview()- overview of POSIX shared memory
sem_close(),
sem_unlink(),
sem_getvalue()

Operating Systems - 1

sem_init
int sem_init(sem_t *sem, int pshared, unsigned int initial_value);
sem_init() initializes the unnamed semaphore at the address pointed to
by sem.
The value :initial value for the semaphore.
If pshared = 0, semaphore is shared between the threads of a process,
(e.g., a global variable, or a variable allocated dynamically on the heap).
If pshared = nonzero, semaphore is shared between processes, located
in a region of shared memory. Forked child can also access the
semaphore.
sem_init() returns 0 on success; on error, -1 is returned, and errno is set
to indicate the error.
Error
EINVAL value exceeds SEM_VALUE_MAX.
ENOSYS pshared is nonzero, but the system does not support
process-shared semaphores (see sem_overview(7)).

Operating Systems - 1

sem_post
int sem_post(sem_t *sem);
sem_post() increments (unlocks) the semaphore pointed to by sem.
If the semaphore's value > 0, then another process or thread
blocked in a sem_wait(3) call will be woken up and proceed to lock
the semaphore.
sem_post() returns 0 on success; on error, the value of the
semaphore is left unchanged, -1 is returned, and errno is set to
indicate the error.
Errors
EINVAL sem is not a valid semaphore.
EOVERFLOW The maximum allowable value for a semaphore would be
exceeded.

Operating Systems - 1

sem_wait
int sem_wait(sem_t *sem);
sem_wait() decrements (locks) the semaphore pointed to by sem.
If the semaphore's value >0, then the decrement proceeds, and the
function returns, immediately.
If the semaphore value =0, then the call blocks until it becomes possible to
perform the decrement (i.e., the semaphore value rises above zero).
return 0 on success; on error, the value of the semaphore is left
unchanged, -1 is returned, and errno is set to indicate the error.
Errors
EINTR The call was interrupted by a signal handler; see signal(7).
EINVAL sem is not a valid semaphore.
ETIMEDOUT The call timed out before the semaphore could be locked.

Operating Systems - 1

Producer and consumer using


semaphore
Program using semaphore library

Operating Systems - 1

Readers-Writers Problem
A data set is shared among a number of concurrent
processes
Readers only read the data set; they do not perform
any updates
Writers can both read and write

Problem allow multiple readers to read at the


same time
Only one single writer can access the shared data at
the same time

Several variations of how readers and writers are


treated all involve priorities
Operating Systems - 1

Readers-Writers Problem (Cont.)


semaphore mutex, wrt;
int readcount;

Data set
Semaphore mutex initialized to 1
Semaphore wrt initialized to 1
Integer readcount initialized to 0

Operating Systems - 1

Readers-Writers Problem (Cont.)


The structure for a writer process
do {
wait (wrt) ;
//

The structure of a reader process

do {
Only one process executes at
wait (mutex) ;
a time to make consistency for
readcount ++ ;
readcount variable
if (readcount == 1)
writing is performed
wait (wrt) ;
To see no process writing
signal (mutex) Allow another to read simultaneously

signal (wrt) ;
} while (TRUE);

// reading is performed
wait (mutex) ;
readcount - - ;
if (readcount == 0)
To allow process for writing signal (wrt) ;
signal (mutex) ;
} while (TRUE);

Operating Systems - 1

Only one process executes at


a time to make consistency for
readcount variable

Readers-Writers Problem
Variations
First variation no reader kept waiting unless writer has
permission to use shared object
Second variation once writer is ready, it performs write
asap
Both may have starvation leading to even more variations
Problem is solved on some systems by kernel providing
reader-writer locks
http://www.cs.uic.edu/~jbell/CourseNotes/OperatingSyste
ms/6_Synchronization.html
Operating Systems - 1

Dining-Philosophers Problem

Philosophers spend their lives thinking and eating


Dont interact with their neighbors, occasionally try to pick up 2 chopsticks (one at a time)
to eat from bowl
Need both to eat, then release both when done
In the case of 5 philosophers
Shared data
Bowl of rice (data set)
Semaphore chopstick [5] initialized to 1

Operating Systems - 1

Dining-Philosophers Problem
Algorithm
The structure of Philosopher i:
do {

P( chopstick[i] );
P(chopStick[ (i + 1) % 5] );
// eat

V( chopstick[i] );
V(chopstick[ (i + 1) % 5] );
// think
} while (TRUE);

What is the problem with this algorithm?


Operating Systems - 1

Problems with Semaphores


Incorrect use of semaphore operations:
V(mutex)
..CS..
P(mutex)
P(mutex)
..CS..
P(mutex)
Omitting of P(mutex) or V(mutex) (or both)

Deadlock and starvation


Operating Systems - 1

Potrebbero piacerti anche