CMSC421: Principles of Operating Systems Nilanjan Banerjee Assistant Professor, University of Maryland Baltimore County nilanb@umbc.edu http://www.csee.umbc.edu/~nilanb/teaching/421/ Principles of Operating Systems Acknowledgments: Some of the slides are adapted from Prof. Mark Corner and Prof. Emery Berger s OS course at Umass Amherst 1
Announcements Readings from Silberchatz [4 th and 6 th chapter] 2
Scheduling Many-one (Green Threads) One-one (linux) Many-many (Window-NT) 3
How does it work in Linux Linux refers to them as tasks rather than threads Thread creation is done through clone() system call clone() allows a child task to share the address space of the parent task (process) struct task_struct points to process data structures (shared or unique) 4
When to use Threads and When to use processes Processes or Threads Performance? Flexibility/Ease-of-use Robustness Simple Scheduling OS has a list of Threads and schedules them similar to Processes. In Linux, threads/processes treated similarly Chooses one of the threads and loads them to be run Runs them for a while, runs another. 5
Flexibility/Ease of use? Process are more flexible Easy to spawn processes, I can ssh into a server and spawn a process Can communicate over sockets= distributes across machines Threads Communicate using memory must be on the same machine Requires thread-safe code 6
Robustness Process are more robust Processes are separate or sandboxed from other processes If one process dies, no effect on other processes Threads If one thread crashes, whole process terminates Since there is sharing, there are problems with using the stack efficiently 7
Context Switch cost Threads much cheaper Stash registers, PC ( IP ), stack pointer Processes above plus Process context TLB shootdown (later in VM lecture) Process switches more expensive, or require long quanta 8
Synchronization and Concurrency Probably the MOST important concept in OS Lets look at a demonstration 9
What really happened? Count = count + 1 load X R1 add Y Z R1 store Y in Mem Thread 1 executes the first two statements and is preempted Thread 2 executes all the three statements Thread 1 returns and executes the third statement 10
Concurrency Terminology Mutual exclusion ( mutex ) prevents multiple threads from entering Critical section code only one thread can execute at a time Lock mechanism for mutual exclusion Lock entering critical section, accessing shared data Unlock when complete Wait if locked Invariant Something that must be true 11
Why do we need concurrency? Synchronization serves two purposes: Ensure safety for shared updates Avoid race conditions Coordinate actions of threads Parallel computation Event notification ALL interleavings must be correct there are lots of interleavings of events also constrain as little as possible 12
Locks/mutexes Provide mutual exclusion to shared data Two routines Rules: acquire wait for lock, then take it release unlock, wake up waiters Acquire lock before accessing shared data Release lock afterwards Lock initially released 13
Locks and Queueing Acquire: if unlocked, go in; otherwise wait in line Release: Unlock & leave 14
Synchronization and Concurrency Demonstration on using pthread locks/mutexes 15
Implementing Locks Requires hardware support (in general) Can build on atomic operations: Load/Store Disable interrupts Uniprocessors only Test & Set, Compare & Swap 16
Disabling Interrupts int value; Queue q; FREE = 0, BUSY = 1 value = 0; q = empty; void acquire () { disable interrupts; if (value == BUSY) { add this thread to q; enable interrupts; sleep(); } else { value = BUSY; } enable interrupts; } } void release () { disable interrupts; if (q not empty) { thread t = q.pop(); put t on ready queue; } value = FREE; enable interrupts; 17
Lock Variants Implementing Locks with Test and Set Blocking Locks Spin locks Hybrids 18
Atomic Operation But: locks are also variables, updated concurrently by multiple threads Who locks the lock? Answer: use hardware-level atomic operations Test-and-set Compare-and-swap 19
Test and Set semantics What s the effect of testandset(value) when: value = 0? ( unlocked ) value = 1? ( locked ) int testandset (int* v) { int old = *v; *v = 1; return old; } 20
Blocking Locks Suspend thread immediately Lets scheduler execute another thread Go to back of run queue or wait to be woken Minimizes time spent waiting But: always causes context switch void blockinglock (Lock& l) { while (testandset(l.v) == 1) { sched_yield(); } } 21
Spin Locks Instead of blocking, loop until released void spinlock (Lock& l) { while (testandset(l.v) == 1) { ; } } 22
Other variants Spin-then-yield: Spin for some time, then yield Fixed spin time Exponential backoff 23
Safety Locks can enforce mutual exclusion, but notorious source of errors Failure to unlock Double locking Deadlock (its own lecture) Priority inversion not an error per se pthread_mutex_t l; void square (void) { pthread_mutex_lock (&l); // acquires lock // do stuff if (x == 0) { return; } else { x = x * x; } pthread_mutex_unlock (&l); } 24
An in-class discussion 25