Title: Critical Sections with lots of Threads
1Critical Sections with lots of Threads
2Refresher Dekers Algorithm
- Assumes two threads, numbered 0 and 1
- CSEnter(int i)
-
- int J i1
- insidei true
- turn J
- while(insideJ turn J)
- continue
- CSExit(int i)
-
- insidei false
3Can we generalize to many threads?
- Obvious approach wont work
- Issue notion of whos turn is next for
breaking ties
- CSEnter(int i)
-
- insidei true
- for(J 0 J lt N J)
- while(insideJ turn J)
- continue
- CSExit(int i)
-
- insidei false
4Bakery concept
- Think of a popular store with a crowded counter,
perhaps the pastry shop in Montreals fancy
market - People take a ticket from a machine
- If nobody is waiting, tickets dont matter
- When several people are waiting, ticket order
determines order in which they can make purchases
5Bakery Algorithm Take 1
- int ticketn
- int next_ticket
- CSEnter(int i)
-
- ticketi next_ticket
- for(J 0 J lt N J)
- while(ticketJ ticketJ lt ticketi)
- continue
- Oops access to next_ticket is a problem!
6Bakery Algorithm Take 2
- CSEnter(int i)
-
- ticketi max(ticket0, ticketN-1)1
- for(J 0 J lt N J)
- while(ticketJ ticketj lt ticketi)
- continue
- Clever idea just add one to the max.
- Oops two could pick the same value!
7Bakery Algorithm Take 3
- If i, j pick same ticket value, ids break tie
- (ticketJ lt ticketi) (ticketJticketi
Jlti) - Notation (B,J) lt (A,i) to simplify the code
- (BltA (BA Jlti)), e.g.
- (ticketJ,J) lt (ticketi,i)
8Bakery Algorithm Take 4
- int ticketN
- boolean pickingN false
CSEnter(int i) ticketi max(ticket0,
ticketN-1)1 for(J 0 J lt N J)
while(ticketJ (ticketJ,J) lt
(ticketi,i)) continue
- Oops i could look at J when J is still storing
its ticket, and yet J could have the lower ticket
number!
9Bakery Algorithm Almost final
- int ticketN
- boolean choosingN false
CSEnter(int i) choosingi true ticketi
max(ticket0, ticketN-1)1 choosingi
false for(J 0 J lt N J) while(choosingJ)
continue while(ticketJ (ticketJ,J) lt
(ticketi,i)) continue
10Bakery Algorithm Issues?
- What if we dont know how many threads might be
running? - The algorithm depends on having an agreed upon
value for N - Somehow would need a way to adjust N when a
thread is created or one goes away - Also, technically speaking, ticket can overflow!
- Solution Change code so that if ticket is too
big, set it back to zero and try again.
11Bakery Algorithm Final
- int ticketN / Important Disable thread
scheduling when changing N / - boolean choosingN false
CSEnter(int i) do ticketi 0
choosingi true ticketi
max(ticket0, ticketN-1)1 choosingi
false while(ticketi gt MAXIMUM) for(J
0 J lt N J) while(choosingJ)
continue while(ticketJ (ticketJ,J) lt
(ticketi,i)) continue
12How do real systems do it?
- Some real systems actually use algorithms such as
the bakery algorithm - A good choice where busy-waiting isnt going to
be super-inefficient - For example, if you have enough CPUs so each
thread has a CPU of its own - Some systems disable interrupts briefly when
calling P() and V() - Some use hardware help atomic instructions
13Critical Sections with Atomic Hardware Primitives
- Process i
- While(test_and_set(lock))
- Critical Section
- lock false
Share int lock Initialize lock false
Assumes that test_and_set is compiled to a
special hardware instruction that sets the lock
and returns the OLD value (true locked false
unlocked)
Problem Does not satisfy liveness (bounded
waiting) (see book for correct solution)
14Presenting critical sections to users
- CSEnter and CSExit are possibilities
- But more commonly, operating systems have offered
a kind of locking primitive - We call these semaphores
15Semaphores
- Non-negative integer with atomic increment and
decrement - Integer S that (besides init) can only be
modified by - P(S) or S.wait() decrement or block if already 0
- V(S) or S.signal() increment and wake up process
if any - These operations are atomic
These systems use the operation signal() instead
of V()
Some systems use the operation wait() instead of
P()
semaphore S P(S) while(S 0)
S--
V(S) S
16Semaphores
- Non-negative integer with atomic increment and
decrement - Integer S that (besides init) can only be
modified by - P(S) or S.wait() decrement or block if already 0
- V(S) or S.signal() increment and wake up process
if any - Can also be expressed in terms of queues
semaphore S P(S) if (S 0) stop thread,
enqueue on wait list, run something else S--
V(S) S if(wait-list isnt empty)
dequeue and start one process
17Summary Implementing Semaphores
- Can use
- Multithread synchronization algorithms shown
earlier - Could have a thread disable interrupts, put
itself on a wait queue, then context switch to
some other thread (an idle thread if needed) - The O/S designer makes these decisions and the
end user shouldnt need to know
18Semaphore Types
- Counting Semaphores
- Any integer
- Used for synchronization
- Binary Semaphores
- Value is limited to 0 or 1
- Used for mutual exclusion (mutex)
Process i P(S) Critical Section V(S)
Shared semaphore S Init S 1