Title: Synchronization
1Synchronization
2Overview
- Concurrency Problems and Mutual Exclusion
Requirements - Software methods with busy-wait
- Hardware Support for Mutual Exclusion
- Software methods without busy-wait
- Semaphores
- Message Passing
3Concurrency Problems
- Interleaved Overlapped computation - both
exhibit similar problems - Ordering access to global resources - leads to
reservation of resources - Reservation of resources leads to inefficient
use. - Lack of reproducibility makes debugging and
testing difficult.
4Example
- int GetTicket(void)
- static customerNbr
- return customerNbr
-
- Fails to give sequential unduplicated tickets
5Vocabulary
- Mutual Exclusion protects a critical resource by
allowing no more than one thread at a time to
execute in a critical section of code which
handles that resource. - Mutual exclusion can lead to deadlock or
starvation
6Win32 Critical Sections
- Works for threads in same process
- CRITICAL_SECTION data structure
- InitializeCriticalSection (cs) or
InitializeCriticalSectionAndSpinCount( cs, cnt) - EnterCriticalSection (cs) or TryEnterCriticalSect
ion(cs) - LeaveCriticalSection(cs)
- Implemented with a semaphore
7Mutual Exclusion Requirements
- Mutual exclusion - at most one thread at a time
can be in the critical section - Threads not in the critical section and not
trying to enter it cannot interfere with those
trying to enter it - No deadlock or starvation possible if no thread
dallies in the critical section
8Software Approaches
- Standard programming methods are both difficult
to code and error prone - Some failed approaches
- Dekkers Algorithm
- Petersons Algorithm
- All make inefficient use of processor because
they spin in busy-wait loops.
9Attempt 1 - Taking Turns
- BOOL turn FALSE
- DoThread(BOOL me)
- DoNonCritical ( )
- while (turn ! me)
- DoCriticalSection( )
- turn !me
- DoMoreNonCritical( )
-
Does Mutual Exclusion without deadlock or
starvation but failure outside of critical
section can prevent other thread from entering.
10Attempt 2 - checking other
- BOOL inside2
- FALSE, FALSE
- DoThread(BOOL me)
- DoNonCritical ( )
- while (inside!me)
- insideme TRUE
- DoCriticalSection ( )
- insideme FALSE
- DoMoreNonCritical ( )
Does not guarantee mutual exclusion
11Attempt 3 - early locking
- BOOL inside2
- FALSE, FALSE
- DoThread(BOOL me)
- DoNonCritical ( )
- insideme TRUE
- while (inside!me)
- DoCriticalSection ( )
- insideme FALSE
- DoMoreNonCritical ( )
Just swap two lines. Does mutual exclusion
but can easily deadlock.
12Attempt 4 - intermittant locks
- DoNonCritical ( )
- do
- insideme FALSE
- Sleep(DELAY)
- insideme TRUE
- while (inside!me)
- DoCriticalSection ( )
- insideme FALSE
- DoMoreNonCritical ( )
Mutual exclusion is achieved but starvation
could result.
13Petersons Algorithm
- BOOL turn, inside2 FALSE, FALSE
- DoThread(BOOL me)
- DoNonCritical ( )
- insideme TRUE
- turn !me
- while (inside!me turn ! me)
- DoCriticalSection ( )
- insideme FALSE
- DoMoreNonCritical ( )
Simpler Algorithm
14Hardware Disabling Interrupts
- Method
- DisableInterrupts( )
- DoCriticalSection ( )
- EnableInterrupts ( )
- Based on thread context switch being triggered by
(clock) interrupt - Works only with uniprocessor
- Reduces total system concurrency
- Intel cli and sti instructions
Works for n threads
15Hardware Test and Set
- Special atomic instruction
- BOOL TestSet (BOOL bitPtr)
- BOOL ret bitPtr
- bitPtr TRUE
- return ret
-
- Intel 386 lock bts mem, reg/imm
- where 2nd operand is bit offset in first
operand
16Using Test Set
- BOOL bit
- DoThread (void c )
- DoNonCritical ( )
- while (TestSet(bit))
- DoCriticalSection ( )
- bit FALSE
- DoMoreNonCritical ( )
Starvation could occur but works for n threads.
17Hardware Exchange
- Special Atomic Instruction
- Exchange(BOOL a, BOOL b)
- BOOL temp a
- a b
- b temp
-
- Intel 386 lock xchg mem, reg
18Using Exchange
- BOOL bit FALSE
- DoThread(void c)
- BOOL key
- DoNonCritical( )
- key TRUE
- do Exchange(bit, key) while (key)
- DoCriticalSection ( )
- bit FALSE
- DoMoreNonCritical ( )
Starvation is possible but works for n
threads.
19Win32 Interlocked Operations
- Allows for atomic operations on DWORD by threads
in same process or otherwise sharing memory - DWORD target must be at even modulo four address
on Intel multiprocessor machines
20Interlocked Operation List
- InterlockedIncrement(PLONG)
- InterlockedDecrement(PLONG)
- InterlockedExchange(PLONG target, LONG value)
- InterlockedExchangeAdd(PLONG Addend, LONG
increment) - InterlockedExchange(PVOID dest, PVOID exchange,
PVOID comperand)
21Hardware Support Summary
- Advantages
- Applies to n threads
- Simple and easy to verify
- Different variables give different locks
- Disadvantages
- Busy-wait wastes cpu resources
- Starvation is possible
- Deadlock is possible -- e.g. waiting on lock held
by lower priority process.
22Counting Semaphores (1 of 2)
- struct semaphore
- DWORD count
- ThreadList tList
-
- void Wait(struct semaphore s)
- if (- - s ? count lt 0)
- EnqueueAndBlock(self, s ? tList)
-
Wait is atomic.
23Counting Semaphores (2 of 2)
- void Signal(struct semaphore s)
- if (s ? count lt 0)
- MoveThreadToRunQueueFrom(
- s ? tList)
-
Signal is atomic.
24Binary Semaphores (1 of 2)
- struct BSemaphore
- BOOL value
- ThreadList tList
-
- void BWait(struct BSemaphore s)
- if (s ? value TRUE)
- s ? value FALSE
- else
- EnqueueAndBlock(self, s ? tList)
BWait is atomic.
25Binary Semaphores (2 of 2)
- void BSignal(struct BSemaphore s)
- if (s ? tList NULL)
- s ? value TRUE
- else
- MoveThreadToRunQueueFrom(
- s ? tList)
-
BSignal is atomic.
26Using Semaphores
- struct semaphore s
- DoThread(void c)
- DoNonCritical( )
- Wait(s)
- DoCriticalSection( )
- Signal(s)
- DoMoreNonCritical( )
Could use Binary Semaphores. Could
have multiple critical sections, etc. Use
TestSet, etc. to implement in operating system.
27Message Passing
- Message Operations
- Send (destination, message)
- Receive (source, message)
- Synchronization
- Send - blocking or non-blocking
- Receive - blocking or non-blocking, may be able
to check for arrived messages - typical non-blocking sends, blocking receives
with arrival check
28Message Addressing
- Direct
- Send has explicit address of addressee
- Receive
- explicit address of sender
- implicit, known only after receipt
- Indirect via mailboxes
- static via permanent ports
- dynamic with connect / disconnect
- Queuing - FIFO, message priorities
29Mutual Exclusion via Messages
- Initialize mbox with 1 message
- DoThread(void c)
- DoNonCritical ( )
- Receive( mbox, message)
- DoCriticalSection ( )
- Send ( mbox, message)
- DoMoreNonCritical ( )
30Producer / Consumer (1 of 2)
- Initialize mayproduce with n messages, mayconsume
as empty - Producer(void c)
- MESSAGE pmsg
- while (TRUE)
- receive(mayproduce, pmsg)
- pmsg Produce( )
- send(mayconsume, pmsg)
-
31Producer / Consumer (2 of 2)
- Consumer(void c)
- MESSAGE cmsg
- while (TRUE)
- Receive(mayconsume, cmsg)
- Consume(cmsg)
- Send(mayproduce, cmsg)
-
-
- Allows multiple servers and clients