Title: Process Synchronization
1Process Synchronization
2Coordination of Processes
- Often, processes need to synchronize their
activities - sharing resources
- when cooperating
- Unfortunately, processes are asynchronous by
nature - Without some means of synchronization race
condition
num numStudents
num numStudents
num
numStudents num
num
numStudents num
3Critical Sections/Regions
- Solution mutual exclusion
- Critical regions (critical sections)
- Criteria for solution to race conditions
- mutual exclusion
- make no assumption about speed, num. CPUs
- no process outside its critical region can block
another - no starvation
4A Naïve Approach Disable Interrupts
- One CPU, if process can disable all interrupts,
can guarantee no race conditions - have to disable interrupts from I/O
- have to disable timer interrupts
- Problem
- too much power for user process -- usurps
kernels power - if anything goes wrong -- may hang entire
computer! - doesnt work for multiple CPUs
- Kernel needs the ability to do this, though
- In some multithreaded applications, this can be
used (e.g., Lisp)
5Another Simple Approach Locks
- Use a single shared variable as a lock
- Could also be a shared file
- Process looks at variable -- if 0, busy waits, if
not set to 0 - Problems
- May not be atomic
- Processes may cheat
- Some processors have special instructions (TSL)
that help this out, though
6Turn-Taking Strict Alternation
- Idea
- non-critical section
- while (turn ! my-turn) / busy wait /
- critical_section()
- turn next_turn(turn)
- non-critical section
- What if one of the processes is faster than the
others? - What if a process is I/O bound?
- Processes block others when not in its critical
region
7Turn-Taking Alternation with Interest(Petersons
Solution)
- Idea -- process declares its interest before it
tries for critical region - Other processes that are interested block if its
not their turn and if someone else who is
interested is in critical section
define FALSE 0 define TRUE 1 define N 2 /
num processes / int turn int interestedN voi
d enter_region(int process) int other
other 1 - process interestedprocess
TRUE turn process while (turn process
interestedother TRUE) void
leave_region(int process) interestedprocess
FALSE
- If only one process ready
- If two processes ready, one in its critical
section - Two processes both simultaneously call
enter_region...
8Bakery Algorithm
- For multiple processes
- Every process that wants to enter critical
section given a number - Lowest number goes first
- Cant guarantee that two wont have same number
- in that case, use tie-breaking convention
BOOLEAN choosingMAXPROC / picking number or
not / int numberMAXPROC / each element
corresponds to a process / void enter(i)
choosingi TRUE / were picking a number
/ numberi find_max(number) 1 / select
next highest number / choosingi FALSE /
done / for (j0 jltn j) while
(choosingj) / busy wait if something is
choosing number / / busy wait till lower
proc. with lower number is done / while (
(numberj ! 0) customer_lt(j,i) )
void leave(i) numberi 0
- What if just one process...?
- What if n, with one in critical region...?
- What if n try to enter critical region at same
time...?
9Hardware Support for Synchronization
- Locks dont work in general
- atomicity
- multiple processors?
- Some processors test-and-set-lock (TSL)
instruction - When TSL executed
- locks memory bus
- then
- sets a register to the value of some memory
location (the lock) - sets the lock to a value meaning locked (e.g.,
1) - then unlocks the memory bus
- Why does this work?
10Mutual Exclusion Using TSL
enter tsl r1,LOCK ! check LOCK cmp r1,0 !
compare old value to 0 jnz enter ! if not zero,
then it was locked, ! so loop ret !
otherwise, return
leave mov LOCK,0 ! just clear the lock ret
11Whats Wrong with Busy Waiting?
- Wastes processor time
- Priority inversion problem
- Example
- Processes busy wait when cant enter critical
region - H high-priority job
- L low-priority job
- Policy always run high-priority jobs when
possible - Scenario
- H waiting on I/O
- L runs, enters critical region
- H I/O completes - context switch to H
- H tries to enter its critical region
- What does H do?
- What does L do?
12Better Idea Blocking
- Make process not runnable instead of busy waiting
- How is this done?
- When does the process wake up?
- Traditional example the bounded buffer problem
- Buffer storage area with n slots
- One process is a producer
- Other is a consumer
- Buffer full producer blocks
- Buffer empty consumer
- Example queues
- Relies on producer waking consumer and vice versa
13Producer/Consumer Problem
define N 100 int count 0 int bufferN pid_t
producer, consumer
void producer() int item while (TRUE)
item produce_item() if (count N)
sleep() enter_item(item) count
if (count 1) wakeup(consumer)
void consumer() int item if (count 0)
sleep() item remove_item() count--
if (count N-1) wakeup(producer)
consume_item(item)
void consume_item(int item)
printf(itemd\n,item)
int produce_item() int item
printf(\nNext item? ) scanf(d,item)
return(item)
14Problems with Sleep/Wakeup
- Signals can be lost due to timing
- producer sees buffer full, but interrupted before
sleep - consumer takes something from buffer, sends
signal -- which is lost - producer goes to sleep
- consumer continues taking stuff out, ultimately
gt sleeps - both are sleeping!
- Can add some machinery to kernel -- bit in PCB,
e.g. -- tells when signal is waiting - But with gt 2 processes, need more bits for the
processes gt arbitrary number of bits needed
15Semaphores
- Motivation problems with blocking
- Idea
- standard way to block processes
- data structure (semaphores) two functions
defined on them - Semaphores
- enforce mutual exclusion
- can be used for producer-consumer problems
- Data structure essentially just an integer --
say, S - Operations
- P(S) -- also known as Down(S) -- decrement S
- V(S) -- also known as Up(S) -- increment S
- Down(S) and S0 block caller.
- Up(S) and process blocked on S gt unblock it
- Down and Up have to be atomic gt system calls
16Semaphores
- One way to implement
- typedef structure semaphore
- int count 1
- queue procs
-
- void Down(semaphore S)
- S.count--
- if (S.count lt 0)
- enqueue(current_proc(),S.procs)
- block(current_proc())
-
-
void Up(semaphore S) process
P S.count if (S.count lt 0) P
dequeue(S.queue) wakeup(P)
17Using Semaphores for Mutual Exclusion
- Traditional name for mutual exclusion semaphore
is mutex - Example from the student roster program before
int num_students int rosterMAXSTUDENTS semapho
re mutex ... void add_student(int id) int
currno Down(mutex) / critical region starts
here / currno num_students rostercurrno
id currno num_students currno / end
critical region / Up(mutex) return ...
18Semaphores and Bounded Buffers
- Single-bounded buffer
- Ex a print queue
- Something else (we wont worry about what right
now) takes items out of the queue - What if the queue is full?
- What if the queue is empty?
- Semaphores needed
- mutex - a binary semaphore
- empty -
- counts empty slots
- initialized to number of slots in queue
19Print Queue Example
- filename bufferSLOTS
- int next_slot 0
- semaphore mutex, empty
- set_count(empty,SLOTS) / would really be set
by daemon / - ...
- void print_file(filename file)
- Down(empty)
- Down(mutex)
- / within critical region now /
- buffernext_slot file
- next_slot
- Up(mutex)
-
- Why is there no Up(empty)?
- What if buffer is empty?
- What if buffer is full?
20Producer/Consumer Problems and Semaphores
- Complete bounded buffer problem
- Ex. Message queue
- process A writes to it
- process B reads from it
- limited size
- Synchronization problem?
- Solution uses three semaphores
- mutex, a binary semaphore
- empty a counting semaphore -- keeps track of
empty slots - full a counting semaphore -- keeps track of full
slots
21Producer/Consumer
- message bufferBUFFSIZE
- semaphore empty, full, mutex
- set_count(empty,BUFFSIZE)
- set_count(full,0)
- void producer()
- message msg
- while (TRUE)
- msg compose_message()
- Down(empty)
- Down(mutex)
- / critical region /
- put_message(buffer,msg)
- / end critical region /
- Up(mutex)
- Up(full)
-
void consumer() message msg while (TRUE)
Down(full) Down(mutex) / critical
region / msg get_message(buffer) / end
critical region / Up(mutex) Up(empty) use
_message(msg)
22Common Problems When Using Semaphores
- Careful not to get carried way with mutex calls!
Dont - void fcn1()
- Down(mutex)
- fcn2()
- Up(mutex)
-
- void fcn2()
- Down(mutex)
- ...
- Up(mutex)
23Problems Using Semaphores
- Careful not to cross semaphore calls
- P1
- Down(S)
- Down(T)
- ...
- Up(T)
- Up(S)
P2 Down(T) Down(S) ... Up(S) Up(T)
24Semaphores in Unix
- POSIX-compliant Unix
- sem_t is the semaphore type
- sem_wait gt Down
- sem_post gt Up
- Used for threads (or processes, if shared)
- Some Unix systems only allocate arrays of
semaphores - semget -- creates a set of semaphores as shared
memory objects, or returns an identifier for such
a set - semop--perform operations on the semaphore set