threads and critical sections vivek pai / kai li princeton university
Post on 22-Dec-2015
218 views
TRANSCRIPT
2
GedankenthreadsWhat happens during fork?We need particular mechanisms, but do we have options about what to do?
3
MechanicsMidterm grading finish
26-30: 131-35: 436-40: 241-45: 546-50: 351-55: 756-60: 661-65: 666-70: 671-75: 776-80: 1
Quiz still not graded
4
Thread and Address Space
ThreadA sequential execution stream within a process (also called lightweight process)
Address spaceAll 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
5
Concurrency and Threads
I/O devicesOverlap I/Os with I/Os and computation (modern OS approach)
Human usersDoing multiple things to the machine: Web browser
Distributed systemsClient/server computing: NFS file server
MultiprocessorsMultiple CPUs sharing the same memory: parallel program
6
Typical Thread APICreation
Fork, Join
Mutual exclusionAcquire (lock), Release (unlock)
Condition variablesWait, Signal, Broadcast
AlertAlert, AlertWait, TestAlert
7
User vs. Kernel-Level Threads
QuestionWhat is the difference between user-level and kernel-level threads?
DiscussionsWhen a user-level thread is blocked on an I/O event, the whole process is blockedA context switch of kernel-threads is expensiveA smart scheduler (two-level) can avoid both drawbacks
8
Thread Control Block
Shared informationProcessor info: parent process, time, etcMemory: segments, page table, and stats, etcI/O and file: comm ports, directories and file descriptors, etc
Private stateState (ready, running and blocked)RegistersProgram counterExecution stack
9
Threads Backed By Kernel Threads
Each thread hasa user stacka private kernel stack
Prosconcurrent accesses to system servicesworks on a multiprocessor
ConsMore memory
Each thread hasa user stacka shared kernel stack with other threads in the same address space
Prosless memoryDoes not work on a multiprocessor
Consserial access to system services
10
“Too Much Milk” Problem
Don’t buy too much milkAny person can be distracted at any point
Person A Person B
Look in fridge: out of milkLeave for WawaArrive at WawaBuy milkArrive home
Look in fridge: out of milkLeave for WawaArrive at WawaBuy milkArrive home
11
A Possible Solution?
Thread can get context switched after checking milk and note, but before buying milk
if ( noMilk ) { if (noNote) { leave note; buy milk; remove note; }}
if ( noMilk ) { if (noNote) { leave note; buy milk; remove note; }}
12
Another Possible Solution?
Thread A switched out right after leaving a note
Thread A
leave noteAif (noNoteB) { if (noMilk) { buy milk }}remove noteA
Thread B
leave noteBif (noNoteA) { if (noMilk) { buy milk }}remove noteB
13
Yet Another Possible Solution?
Safe to buyIf the other buys, quit
Thread A
leave noteAwhile (noteB) do nothing;if (noMilk) buy milk;remove noteA
Thread B
leave noteBif (noNoteA) { if (noMilk) { buy milk }}remove noteB
14
RemarksThe last solution works, but
Life is too complicatedA’s code is different from B’sBusy waiting is a waste
Peterson’s solution is also complexWhat we want is:
Acquire(lock);if (noMilk) buy milk;Release(lock);
} Critical section
15
What Is A Good SolutionOnly one process inside a critical sectionNo assumption about CPU speedsProcesses outside of critical section should not block other processesNo one waits foreverWorks for multiprocessors
16
PrimitivesWe want to avoid thinking (repeatedly)So, we want some “contract” that provides certain behaviorLow-level behavior encapsulated in “primitives”Application uses primitives to construct more complex behavior
17
The Simplistic Acquire/Release
Kernel cannot let users disable interruptsCritical sections can be arbitrarily longUsed on uniprocessors, but won’t work on multiprocessors
Acquire() { disable interrupts;}
Release() { enable interrupts;}
18
Disabling Interrupts
Done right, serializes activityPeople think sequentially – easier to reasonGuarantees code executes without interruption
Delays handling of external events
Used throughout the kernel
19
Using Disabling Interrupts
Why do we need to disable interrupts at all?Why do we need to enable interrupts inside the loop in Acquire?
Acquire(lock) { disable interrupts; while (lock != FREE){ enable interrupts; disable interrupts; } lock = BUSY; enable interrupts;}
Release(lock) { disable interrupts; lock = FREE; enable interrupts;}
20
Using Disabling Interrupts
When does Acquire re-enable interrupts in going to sleep?
Before enqueue?After enqueue but before block?
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;}
21
Hardware Support for Mutex
Mutex = mutual exclusionEarly software-only approaches limitedHardware support became commonVarious approaches:
Disabling interruptsAtomic memory load and storeAtomic 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
22
The Big PictureConcurrent Applications
Locks Semaphores Monitors Send/Receive
Load/Store Interrupt disable Test&Set
High-LevelAtomic API
Low-LevelAtomic Ops
Interrupt (timer or I/O completion), Scheduling, Multiprocessor
23
Atomic Read-Modify-Write Instructions
Test&Set: Read value and write 1 back to memoryExchange (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 x86Load link and conditional store (MIPS, Alpha)
Read value in one instruction, do some operationsWhen store, check if value has been modified. If not, ok; otherwise, jump back to start
24
A Simple Solution with Test&Set
Waste CPU timeLow priority threads may never get a chance to run
Acquire(lock) { while (!TAS(lock)) ;}
Release(lock) { lock = 0;}
25
Test&Set, Minimal Busy Waiting
Why does this work?
Acquire(lock) { while (!TAS(lock.guard)) ; if (lock.value) { enqueue the thread; block and lock.guard = 0; } else { lock.value = 1; lock.guard = 0; }}
Release(lock) { while (!TAS(lock.guard)) ; if (anyone in queue) { dequeue a thread; make it ready; } else lock.value = 0; lock.guard = 0;}