Title: Threads and Critical Sections
1Threads and Critical Sections
- Vivek Pai / Kai Li
- Princeton University
2Gedankenthreads
- What happens during fork?
- We need particular mechanisms, but do we have
options about what to do?
3Mechanics
- Midterm grading finish
- 26-30 1
- 31-35 4
- 36-40 2
- 41-45 5
- 46-50 3
- 51-55 7
- 56-60 6
- 61-65 6
- 66-70 6
- 71-75 7
- 76-80 1
- Quiz still not graded
4Thread and Address Space
- Thread
- A sequential execution stream within a process
(also called lightweight process) - Address space
- All the state needed to run a program
- Provide illusion that program is running on its
own machine (protection) - There can be more than one thread per address
space
5Concurrency and Threads
- I/O devices
- Overlap I/Os with I/Os and computation (modern OS
approach) - Human users
- Doing multiple things to the machine Web browser
- Distributed systems
- Client/server computing NFS file server
- Multiprocessors
- Multiple CPUs sharing the same memory parallel
program
6Typical Thread API
- Creation
- Fork, Join
- Mutual exclusion
- Acquire (lock), Release (unlock)
- Condition variables
- Wait, Signal, Broadcast
- Alert
- Alert, AlertWait, TestAlert
7User vs. Kernel-Level Threads
- Question
- What is the difference between user-level and
kernel-level threads? - Discussions
- When a user-level thread is blocked on an I/O
event, the whole process is blocked - A context switch of kernel-threads is expensive
- A smart scheduler (two-level) can avoid both
drawbacks
8Thread Control Block
- Shared information
- Processor info parent process, time, etc
- Memory segments, page table, and stats, etc
- I/O and file comm ports, directories and file
descriptors, etc - Private state
- State (ready, running and blocked)
- Registers
- Program counter
- Execution stack
9Threads Backed By Kernel Threads
- Each thread has
- a user stack
- a private kernel stack
- Pros
- concurrent accesses to system services
- works on a multiprocessor
- Cons
- More memory
- Each thread has
- a user stack
- a shared kernel stack with other threads in the
same address space - Pros
- less memory
- Does not work on a multiprocessor
- Cons
- serial access to system services
10Too Much Milk Problem
Person A
Person B
Look in fridge out of milk Leave for Wawa Arrive
at Wawa Buy milk Arrive home
Look in fridge out of milk Leave for Wawa Arrive
at Wawa Buy milk Arrive home
- Dont buy too much milk
- Any person can be distracted at any point
11A Possible Solution?
if ( noMilk ) if (noNote) leave note
buy milk remove note
if ( noMilk ) if (noNote) leave note
buy milk remove note
- Thread can get context switched after checking
milk and note, but before buying milk
12Another Possible Solution?
Thread A
Thread B
leave noteA if (noNoteB) if (noMilk)
buy milk remove noteA
leave noteB if (noNoteA) if (noMilk)
buy milk remove noteB
- Thread A switched out right after leaving a note
13Yet Another Possible Solution?
Thread A
Thread B
leave noteA while (noteB) do nothing if
(noMilk) buy milk remove noteA
leave noteB if (noNoteA) if (noMilk)
buy milk remove noteB
- Safe to buy
- If the other buys, quit
14Remarks
- The last solution works, but
- Life is too complicated
- As code is different from Bs
- Busy waiting is a waste
- Petersons solution is also complex
- What we want is
Acquire(lock) if (noMilk) buy
milk Release(lock)
Critical section
15What Is A Good Solution
- Only one process inside a critical section
- No assumption about CPU speeds
- Processes outside of critical section should not
block other processes - No one waits forever
- Works for multiprocessors
16Primitives
- We want to avoid thinking (repeatedly)
- So, we want some contract that provides certain
behavior - Low-level behavior encapsulated in primitives
- Application uses primitives to construct more
complex behavior
17The Simplistic Acquire/Release
Acquire() disable interrupts
Release() enable interrupts
- Kernel cannot let users disable interrupts
- Critical sections can be arbitrarily long
- Used on uniprocessors, but wont work on
multiprocessors
18Disabling Interrupts
- Done right, serializes activity
- People think sequentially easier to reason
- Guarantees code executes without interruption
- Delays handling of external events
- Used throughout the kernel
19Using Disabling Interrupts
Acquire(lock) disable interrupts while
(lock ! FREE) enable interrupts
disable interrupts lock BUSY enable
interrupts
Release(lock) disable interrupts lock
FREE enable interrupts
- Why do we need to disable interrupts at all?
- Why do we need to enable interrupts inside the
loop in Acquire?
20Using Disabling Interrupts
Acquire(lock) disable interrupts while
(lock BUSY) enqueue me for lock
block else lock BUSY enable
interrupts
Release(lock) disable interrupts if
(anyone in queue) dequeue a thread
make it ready lock FREE enable
interrupts
- When does Acquire re-enable interrupts in going
to sleep? - Before enqueue?
- After enqueue but before block?
21Hardware Support for Mutex
- Mutex mutual exclusion
- Early software-only approaches limited
- Hardware support became common
- Various approaches
- Disabling interrupts
- Atomic memory load and store
- Atomic read-modify-write
- L. Lamport, A Fast Mutual Exclusion Algorithm,
ACM Trans. on Computer Systems, 5(1)1-11, Feb
1987. use Google to find
22The Big Picture
Concurrent Applications
High-Level Atomic API
Locks Semaphores Monitors Send/Receive
Low-Level Atomic Ops
Load/Store Interrupt disable TestSet
Interrupt (timer or I/O completion), Scheduling,
Multiprocessor
23Atomic Read-Modify-Write Instructions
- TestSet Read value and write 1 back to memory
- Exchange (xchg, x86 architecture)
- Swap register and memory
- Compare and Exchange (cmpxchg, 486)
- If Dest (al,ax,eax), Dest SRC
- else (al,ax,eax) Dest
- LOCK prefix in x86
- Load link and conditional store (MIPS, Alpha)
- Read value in one instruction, do some operations
- When store, check if value has been modified. If
not, ok otherwise, jump back to start
24A Simple Solution with TestSet
Acquire(lock) while (!TAS(lock))
Release(lock) lock 0
- Waste CPU time
- Low priority threads may never get a chance to run
25TestSet, Minimal Busy Waiting
Release(lock) while (!TAS(lock.guard))
if (anyone in queue) dequeue a thread
make it ready else lock.value 0
lock.guard 0
Acquire(lock) while (!TAS(lock.guard))
if (lock.value) enqueue the thread
block and lock.guard 0 else
lock.value 1 lock.guard 0