Transcript Process P 0
Mutual Exclusion -- Addendum
Mutual Exclusion in Critical
Sections
RoadMap
Today there are libraries that provide
application programmers with semaphores
Semaphores are used by programmers to
provide for critical sections
Let’s first talk about semaphores and then
the OS support for them.
What is a semaphore?
A semaphore is an integer variable with the
following three operations.
1.
2.
Initialize: You can initialize the semaphore to any
non-negative value.
Decrement: The down operation
•
•
3.
Semaphore value > 0: Decrement by 1.
Semaphore value == 0: If value is 0, the process blocks (gets
put into queue). It is said to be sleeping on the semaphore..
Increment: The up operation.
• Semaphore value == 0 and some processes are sleeping on the
semaphore, one is unblocked. Otherwise, value is
incremented.
What is a Semaphore?
Use down before entering a critical section
Use up after finishing with a critical
section i.e.,
Example: Assume S is initialized to 1.
………
down(S);
//critical section
up(S);
Using Semaphores
Process P0
Process P1
………………..
down(S);
//critical section
up(S);
………………..
………………..
down(S);
//critical section
up(S);
………………..
Using Semaphores
Process P0
down(S);
critical section
up(S);
Process P1
down(S);
critical section
up(S);
Initialize the semaphore variable, S, to 1
Why not zero?
Using Semaphores
Process P0
down(S);
critical section
up(S);
Process P1
down(S);
critical section
up(S);
Now what would happen if P0 executes the down
operation?
The semaphore S is currently 1.
It becomes 0 and P0 enters the critical section
Using Semaphores
Process P0
down(S);
critical section
up(S);
Process P1
down(S);
critical section
up(S);
Now what would happen if P1 executes the down
operation?
The semaphore S is currently 0
P1 blocks
Using Semaphores
Process P0
down(S);
critical section
up(S);
Process P1
down(S);
critical section
up(S);
Assume now that P0 is done with the
critical section
It calls the up function
P1
is unblocked
If there was no process waiting to enter the
critical section the value of s would become one
Using Semaphores
What happens if there are three processes:
P0,P1,P2
Assume P0 enters its critical section
If P1 and P2 execute the down operation they will
block
When P0 leaves the critical section then P1 is
unblocked allowing P1 to enter its critical section
P2 is still blocked
What if P0 wants to enter its critical section again
when P1 is in it?
Using Semaphores
What if we want to allow 10 processes to
use a critical section?
How would we initialize a semaphore, s?
Semaphore
Binary Semaphore: Value is either 0 or 1
Often referred to as a mutex
Counting Semaphore: Value ranges from 0
to N where N can be any integer number
Deadlock
Deadlock – Two or more processes are
waiting indefinitely for an event that can
be caused by only one of the waiting
processes
Something to watch for
Deadlock
Example: Let S and Q be two semaphores
initialized to one
Process P0
down(S);
down(Q);
……
up(S);
up(Q);
Process P1
down(Q);
down(S);
….
up(Q);
up(S);
Implementation
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
Implementation
A semaphore can be defined as a C struct
along these lines:
typedef struct {
int value;
struct process *list;
} semaphore
Implementation
down() operation can be defined as
down(semaphore *S) {
S->value--;
if (S->value < 0) {
add this process to S->list;
block();
}
}
The block() operation suspends the process
that invokes it.
Implementation
up() operation can be defined as
up(semaphore *S) {
S->value++;
if (S->value <= 0) {
remove process P from S->list;
wakeup(P);
}
}
The wakeup() operation sends a signal that
represents an event that the invoking
process is no longer in the critical section
Implementation
BTW, the implementation just described is
how Linux implements semaphores
The up and down operations represent
require access to a critical section which is
the semaphore variable
Need hardware/OS support e.g.,
Hardware support e.g., TSL.
Signals
Synchronization Hardware
Any solution to the
critical section problem
requires a lock
Process must acquire a
lock before entering a
critical section
Process must release
the lock when it exists
the critical section.
We will present a
hardware solution
while (true) {
acquire lock
critical section
release lock
other
}
Test and Lock Instruction
(TSL)
Many computers have the following type of
instruction: TSL REGISTER, LOCK
One use of this instruction is to provide a
lock for a critical region such code that
operations on a semaphore variable
Using the TSL Instruction
TSL
enter_region:
TSL Register, Lock
CMP Register, #0
JNE enter_region
RET //to caller
leave_region:
move Lock, #0
RET
TSL Register, Lock
Reads LOCK into register REGISTER
Stores a nonzero value at the memory location
LOCK
The operations of reading the word and storing
it are guaranteed to be indivisible
TSL
enter_region:
TSL Register, Lock
CMP Register, #0
JNE enter_region
RET //to caller
leave_region:
move Lock, #0
RET
TSL Register, Lock
The CPU executing the TSL instruction locks
the memory bus to prohibit other CPUs from
accessing memory until the TSL instruction is
done
TSL
enter_region:
TSL Register, Lock
CMP Register, #0
JNE enter_region
RET //to caller
leave_region:
move Lock, #0
RET
CMP Register, #0
Compare register value with 0
JNE Enter_Region
If Register value is not 0 then go to the start
of enter region
TSL
enter_region:
TSL Register, Lock
CMP Register, #0
JNE enter_region
RET //to caller
leave region:
move Lock, #0
RET
Return to caller only if Register value is 0
TSL
enter_region:
TSL Register, Lock
CMP Register, #0
JNE enter_region
RET //to caller
leave_region:
move Lock, #0
RET
Before entering its critical region, a
process calls enter_region
What if LOCK is 1?
Busy wait until lock is 0
When leaving the critical section, a process
calls leave_region
Using TSL
enter_region:
TSL Register, Lock
CMP Register, #0
JNE enter_region
RET //to caller
leave_region:
move Lock, #0
RET
Assume two processes: P0 and P1
LOCK is initialized to zero
Using TSL
enter_region:
TSL Register, Lock
CMP Register, #0
JNE enter_region
RET //to caller
leave_region:
move Lock, #0
RET
Assume that P0 wants to enter the critical
section
It executes the TSL instruction.
The register value is 0 which reflects the value
of LOCK
LOCK is set to 1
Using TSL
enter_region:
leave_region:
TSL Register, Lock
move Lock, #0
CMP Register, #0
RET
JNE enter_region
RET //to caller
Now P1 wants to enter the critical section;
It executes the TSL instruction
The register value is 1 which reflects the value
of LOCK
P1 cannot enter the critical section
It repeats the TSL instruction and comparison
operation until it can get into the critical
section
Using TSL
enter_region:
TSL Register, Lock
CMP Register, #0
JNE enter_region
RET //to caller
leave_region:
move Lock, #0
RET
P0 is done with the critical section
LOCK becomes 0
Using TSL
Enter_region:
TSL Register, Lock
CMP Register, #0
JNE enter_region
RET //to caller
leave_region:
move Lock, #0
RET
The next time P1 executes the TSL
instruction and comparison operation it
finds that the register value (which
reflects LOCK) is zero. It can now enter
the critical section.
Implementing TSL
Implementing atomic TSL instructions on
multiprocessors is not trivial.
This is a subject for a computer
architecture course
Signals
A signal is used in UNIX systems to notify
a process that a particular event has
occurred
A signal is generated by the occurrence of a
particular event
A generated signal is delivered to a process
Once delivered, the signal must be handled
A signal process is used to associate
computation with a signal
Signals
Example
<control> <C> is entered
This causes an event to be generated to a
running process that is in the foreground
When that process receives the event it
executes a signal handler which terminates the
process
Signals
Two possible handlers
Default signal handler: Provided by kernel
User-defined signal handler: Provided by user
and overrides the default
What if a process has multiple threads?
How a signal is handled depends on the type of
signal. Options
• Deliver the signal to the thread to which the signal
applies
• Deliver the signal to every thread in the process
• Deliver the signal to certain threads in the process
• Assign a specific threa to receive all signals for the
process
Semaphore Implementation
When the up is executed a blocked
process is woken up. This is done using
signals
Semaphore operations are critical sections
– use TSL.
Questions
How are multiple processes prevented from
being in the critical section ?
Why different than disabling interrupts?
Which is better in a multicore system?
Disabling interrupts or TSL test?
Question
Assume that instead of a TSL instruction
there is an instruction to swap the
contents of a register and memory word in
a single indivisible action.
Can
this
you write a enter_region routine based on
Mars PathFinder
Priority Inversion: Scheduling problem
when lower-priority process holds a lock
needed by higher-priority process
Now back to the Mars Pathfinder problem
High priority task was taking longer than
expected to complete its work
The task was forced to wait for a shared
resource that was being held by a lowerpriority process
Lower-priority process was being pre-empted
by a medium priority process
Scheduler detected problem and would reset
Mars PathFinder
The fix
The OS had a global variable to enable priority
inheritance on all semaphores
It was off
It was set to on and then everything worked
Summary
Defined race condition
Examined different solutions