+ All Categories
Home > Documents > CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project...

CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project...

Date post: 20-Jan-2016
Category:
Upload: moses-thomas
View: 217 times
Download: 0 times
Share this document with a friend
23
CS 3204 Operating Systems Godmar Back Lecture 7
Transcript
Page 1: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

CS 3204Operating Systems

Godmar Back

Lecture 7

Page 2: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 2

Announcements

• Project 1 due on Sep 29, 11:59pm

• Reading: – Read carefully 1.5, 3.1-3.3, 6.1-6.4

• Dr. Back has no office hours this week

Page 3: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 3

Project 1 Suggested Timeline

• By now, you have:– Have read relevant project documentation, set up CVS, built and

run your first kernel, designed your data structures for alarm clock

• And should be finishing:– Alarm clock by Sep 16

• Pass all basic priority tests by Sep 18• Priority Inheritance & Advanced Scheduler will take the

most time to implement & debug, start them in parallel– Should have design for priority inheritance figured out by Sep 23– Develop & test fixed-point layer independently by Sep 23

• Due date Sep 29

Page 4: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

Concurrency & Synchronization

Page 5: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 5

Overview

• Will talk about locks, semaphores, and monitors/condition variables

• For each, will talk about:– What abstraction they represent– How to implement them– How and when to use them

• Two major issues:– Mutual exclusion– Scheduling constraints

• Project note: Pintos implements its locks on top of semaphores

Page 6: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 6

Critical Section Problem

• A solution for the CS Problem must1) Provide mutual exclusion: at most one thread can be inside CS2) Guarantee Progress: (no deadlock)

• if more than one threads attempt to enter, one will succeed• ability to enter should not depend on activity of other threads not

currently in CS

3) Bounded Waiting: (no starvation)• A thread attempting to enter critical section eventually will

(assuming no thread spends unbounded amount of time inside CS)

• A solution for CS problem should be– Fair (make sure waiting times are balanced)– Efficient (not waste resources)– Simple

Page 7: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 7

Locks

• Thread that enters CS locks it– Others can’t get in and have to wait

• Thread unlocks CS when leaving it– Lets in next thread– which one?

• FIFO guarantees bounded waiting

• Highest priority in Proj1

• Can view Lock as an abstract data type– Provides (at least) init, acquire, release

lock

unlock

Page 8: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 8

Implementing Locks

• Locks can be implemented directly, or – among other options - on top of semaphores– If implemented on top of semaphores, then

semaphores must be implemented directly– Will explain this layered approach first to help

in understanding project code– Issues in direct implementation of locks apply

to direct implementation of semaphores as well

Page 9: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 9

Semaphores

• Invented by Edsger Dijkstra in 1960s• Counter S, initialized to some value, with two operations:

– P(S) or “down” or “wait” – if counter greater than zero, decrement. Else wait until greater than zero, then decrement

– V(S) or “up” or “signal” – increment counter, wake up any threads stuck in P.

• Semaphores don’t go negative: – #V + InitialValue - #P >= 0

• Note: direct access to counter value after initialization is not allowed

• Counting vs Binary Semaphores– Binary: counter can only be 0 or 1

• Simple to implement, yet powerful– Can be used for many synchronization problems

Source: inter.scoutnet.org

Page 10: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 10

Semaphores as Locks

• Semaphores can be used to build locks– Pintos does just that

• Must initialize semaphore with 1 to allow one thread to enter critical section

• Easily generalized to allow at most N simultaneous threads: multiplex pattern (i.e., a resource can be accessed by at most N threads)

semaphore S(1); // allows initial down

lock_acquire(){ // try to decrement, wait if 0 sema_down(S);}

lock_release(){ // increment (wake up waiters if any) sema_up(S);}

semaphore S(1); // allows initial down

lock_acquire(){ // try to decrement, wait if 0 sema_down(S);}

lock_release(){ // increment (wake up waiters if any) sema_up(S);}

Page 11: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 11

Implementing Locks Directly

• NB: Same technique applies to implementing semaphores directly (as in done in Pintos)– Will see two applications of the same technique

• Different solutions exist to implement locks for uniprocessor and multiprocessors

• Will talk about how to implement locks for uniprocessors first – next slides all assume uniprocessor

Page 12: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 12

Implementing Locks, Take 1

• Does this work?

lock_acquire(struct lock *l){ while (l->state == LOCKED)

continue; l->state = LOCKED;}

lock_acquire(struct lock *l){ while (l->state == LOCKED)

continue; l->state = LOCKED;}

lock_release(struct lock *l){ l->state = UNLOCKED;}

lock_release(struct lock *l){ l->state = UNLOCKED;}

No – does not guarantee mutual exclusion property – more than onethread may see “state” in UNLOCKED state and break out of whileloop. This implementation has itself a race condition.

Page 13: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 13

Implementing Locks, Take 2

• Does this work?

lock_acquire(struct lock *l){ disable_preemption(); while (l->state == LOCKED)

continue; l->state = LOCKED; enable_preemption();}

lock_acquire(struct lock *l){ disable_preemption(); while (l->state == LOCKED)

continue; l->state = LOCKED; enable_preemption();}

lock_release(struct lock *l){ l->state = UNLOCKED;}

lock_release(struct lock *l){ l->state = UNLOCKED;}

No – does not guarantee progress property. If one thread enters thewhile loop, no other thread will ever be scheduled since preemptionis disabled – in particular, no thread that would call lock_release willever be scheduled.

Page 14: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 14

Implementing Locks, Take 3

• Does this work?

lock_acquire(struct lock *l){ while (true) { disable_preemption(); if (l->state == UNLOCKED) { l->state = LOCKED; enable_preemption(); return; } enable_preemption(); }}

lock_acquire(struct lock *l){ while (true) { disable_preemption(); if (l->state == UNLOCKED) { l->state = LOCKED; enable_preemption(); return; } enable_preemption(); }}

lock_release(struct lock *l){ l->state = UNLOCKED;}

lock_release(struct lock *l){ l->state = UNLOCKED;}

Yes, this works – but is grossly inefficient. A thread that encountersthe lock in the LOCKED state will busy wait until it is unlocked,needlessly using up CPU time.

Page 15: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 15

Implementing Locks, Take 4lock_acquire(struct lock *l){ disable_preemption(); while (l->state == LOCKED) { list_push_back(l->waiters, &current->elem); thread_block(current); } l->state = LOCKED; enable_preemption();}

lock_acquire(struct lock *l){ disable_preemption(); while (l->state == LOCKED) { list_push_back(l->waiters, &current->elem); thread_block(current); } l->state = LOCKED; enable_preemption();}

lock_release(struct lock *l){ disable_preemption(); l->state = UNLOCKED; if (list_size(l->waiters) > 0) thread_unblock( list_entry(list_pop_front(l->waiters), struct thread, elem)); enable_preemption();}

lock_release(struct lock *l){ disable_preemption(); l->state = UNLOCKED; if (list_size(l->waiters) > 0) thread_unblock( list_entry(list_pop_front(l->waiters), struct thread, elem)); enable_preemption();}

Correct & uses proper blocking.Note that thread doing the unlock performs the work of unblockingthe first waiting thread.

Page 16: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 16

Multiprocessor Locks

• Can’t stop threads running on other processors– too expensive (interprocessor irq)– also would create conflict with protection (locking =

unprivileged op, stopping = privileged op), involving the kernel in *every* acquire/release

• Instead: use atomic instructions provided by hardware– E.g.: test-and-set, atomic-swap, compare-and-

exchange, fetch-and-add– All variations of “read-and-modify” theme

• Locks are built on top of these

Page 17: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 17

Atomic Swap

// In C, an atomic swap instruction would look like thisvoidatomic_swap(int *memory1, int *memory2){

[ disable interrupts in CPU; lock cache line(s) for other processors ]

int tmp = *memory1;*memory1 = *memory2;*memory2 = tmp;

[ unlock cache line(s); reenable interrupts ]}

// In C, an atomic swap instruction would look like thisvoidatomic_swap(int *memory1, int *memory2){

[ disable interrupts in CPU; lock cache line(s) for other processors ]

int tmp = *memory1;*memory1 = *memory2;*memory2 = tmp;

[ unlock cache line(s); reenable interrupts ]}

CPU1CPU1 CPU2CPU2

MemoryMemory

memory bus

CacheCache CacheCache

cache coherenceprotocol

Page 18: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 18

Spinlocks

lock_acquire(struct lock *l){ int lockstate = LOCKED; while (lockstate == LOCKED) { atomic_swap(&lockstate, &l->state); }}

lock_acquire(struct lock *l){ int lockstate = LOCKED; while (lockstate == LOCKED) { atomic_swap(&lockstate, &l->state); }}

lock_release(struct lock *l){ l->state = UNLOCKED;}

lock_release(struct lock *l){ l->state = UNLOCKED;}

• Thread spins until it acquires lock– Q1: when should it block instead?– Q2: what if spin lock holder is preempted?

Page 19: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 19

Spinning vs Blocking

• Some lock implementations combine spinning and blocking locks

• Blocking has a cost– Shouldn’t block if lock becomes available in

less time than it takes to block

• Strategy: spin for time it would take to block– Even in worst case, total cost for lock_acquire

is less than 2*block time

Page 20: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 20

Spinlocks vs Disabling Preemption

• What if spinlocks were used on single CPU? Consider: – thread 1 takes spinlock– thread 1 is preempted– thread 2 with higher priority runs– thread 2 tries to take spinlock, finds it taken– thread 2 spins forever deadlock!

• Thus in practice, usually combine spinlocks with disabling preemption– E.g., spin_lock_irqsave() in Linux

• UP kernel: reduces to disable_preemption()• SMP kernel: disable_preemption() + spinlock

• Spinlocks are used when holding resources for small periods of time (same rule as for when it’s ok to disable irqs)

Page 21: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 21

Critical Section Efficiency

• As processors get faster, CSE decreases because atomic instructions become relatively more expensive Source: McKenney, 2005

Page 22: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 22

Spinlocks (Faster)

lock_acquire(struct lock *l){ int lockstate = LOCKED; while (lockstate == LOCKED) { while (l->state == LOCKED) continue; atomic_swap(&lockstate, &l->state); }}

lock_acquire(struct lock *l){ int lockstate = LOCKED; while (lockstate == LOCKED) { while (l->state == LOCKED) continue; atomic_swap(&lockstate, &l->state); }}

lock_release(struct lock *l){ l->state = UNLOCKED;}

lock_release(struct lock *l){ l->state = UNLOCKED;}

• Only try “expensive” atomic_swap instruction if you’ve seen lock in unlocked state

Page 23: CS 3204 Operating Systems Godmar Back Lecture 7. 12/12/2015CS 3204 Fall 20082 Announcements Project 1 due on Sep 29, 11:59pm Reading: –Read carefully.

04/21/23CS 3204 Fall 2008 23

Locks: Ownership & Recursion

• Locks typically (not always) have notion of ownership– Only lock holder is allowed to unlock– See Pintos lock_held_by_current_thread()

• What if lock holder tries to acquire locks it already holds?– Nonrecursive locks: deadlock!– Recursive locks:

• inc counter• dec counter on lock_release• release when zero


Recommended