threads and critical sections vivek pai / kai li princeton university

25
Threads and Critical Sections Vivek Pai / Kai Li Princeton University

Post on 22-Dec-2015

218 views

Category:

Documents


0 download

TRANSCRIPT

Threads and Critical Sections

Vivek Pai / Kai LiPrinceton University

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;}