CPS 310 Threads and Concurrency: Topics

CPS 310 Threads and Concurrency: Topics

D u k e S y s t e m s CPS 310 Threads and Concurrency: Topics Jeff Chase Duke University hp://www.cs.duke.edu/~chase/cps310 Terminology and syntax • The abstractions for concurrency control in this class are now sort-of universal at the OS/API level. • Monitors (mutex+CV) with Mesa semantics appear in: – Java (e.g., on Android) and JVM languages (e.g., Scala) – POSIX threads or Pthreads (used on Linux and MacOS/iOS) – Windows, C#/.NET, and other Microsoft systems • Terminology and APIs vary a bit. – mutex == lock == Java “synchronized” – monitor == mutex + condition variable (CV) – signal() == notify(), broadcast() == notifyAll() • The slides use interchangeable terms interchangeably. Example: the soda/HFCS machine Soda drinker Delivery person (consumer) (producer) Vending machine (buffer) Producer-consumer code consumer () { producer () { take a soda from machine add one soda to machine } } Solving producer-consumer 1. What are the variables/shared state? ê Soda machine buffer ê Number of sodas in machine (≤ MaxSodas) 2. Locks? ê 1 to protect all shared state (sodaLock) 3. Mutual exclusion? ê Only one thread can manipulate machine at a time 4. Ordering constraints? ê Consumer must wait if machine is empty (CV hasSoda) ê Producer must wait if machine is full (CV hasRoom) Producer-consumer code consumer () { producer () { lock lock take a soda from machine add one soda to machine unlock unlock } } Producer-consumer code consumer () { producer () { lock lock wait if empty wait if full take a soda from machine add one soda to machine notify (not full) notify (not empty) unlock unlock } } Producer-consumer code consumer () { producer () { lock (sodaLock) lock (sodaLock) while (numSodas == 0) { while(numSodas==MaxSodas){ wait (sodaLock,hasSoda) wait (sodaLock, hasRoom) } Mx CV1 } Mx CV2 take a soda from machine add one soda to machine signal (hasRoom) signal (hasSoda) CV2 CV1 unlock (sodaLock) unlock (sodaLock) } } Producer-consumer code synchronized consumer () { synchronized producer () { while(numSodas==maxSodas) { while (numSodas == 0) { wait () o.wait () } } put a soda from machine take a soda from machine notify(); notify(); } } Producer-consumer code consumer () { synchronized(o) { while (numSodas == 0) { o.wait () } take a soda o.notify(); } } Producer-consumer code consumer () { producer () { lock (sodaLock) lock (sodaLock) while (numSodas == 0) { while(numSodas==MaxSodas){ wait (sodaLock,hasSoda) wait (sodaLock, hasRoom) } } take a soda from machine fill machine with soda signal(hasRoom) broadcast(hasSoda) unlock (sodaLock) unlock (sodaLock) } } The signal should be a broadcast if the producer can produce more than one resource, and there are mulple consumers. lpcox slide edited by chase Variations: looping producer producer () { ê Producer lock (sodaLock) while (1) { ê Infinite loop ok? while(numSodas==MaxSodas){ wait (sodaLock, hasRoom) ê Why/why not? } ê Release lock in add soda to machine wait call signal (hasSoda) } unlock (sodaLock) } Variations: resting producer producer () { ê Producer lock (sodaLock) while (1) { ê Sleep ok? sleep (1 hour) while(numSodas==MaxSodas){ ê Why/why not? wait (sodaLock, hasRoom) } ê Shouldn’t hold add soda to machine locks during a slow operation signal (hasSoda) } unlock (sodaLock) } Variations: one CV? consumer () { producer () { lock (sodaLock) lock (sodaLock) while (numSodas == 0) { while(numSodas==MaxSodas){ wait (sodaLock,hasRorS) wait (sodaLock,hasRorS) } Mx CV } Mx CV take a soda from machine add one soda to machine signal (hasRorS) signal(hasRorS) CV CV unlock (sodaLock) unlock (sodaLock) } } Two producers, two consumers: who consumes a signal? ProducerA and ConsumerB wait while ConsumerC signals? Variations: one CV? consumer () { producer () { lock (sodaLock) lock (sodaLock) while (numSodas == 0) { while(numSodas==MaxSodas){ wait (sodaLock,hasRorS) wait (sodaLock,hasRorS) } } take a soda from machine add one soda to machine signal (hasRorS) signal (hasRorS) unlock (sodaLock) unlock (sodaLock) } } Is it possible to have a producer and consumer both waing? max=1, cA and cB wait, pC adds/signals, pD waits, cA wakes Variations: one CV? consumer () { producer () { lock (sodaLock) lock (sodaLock) while (numSodas == 0) { while(numSodas==MaxSodas){ wait (sodaLock,hasRorS) wait (sodaLock,hasRorS) } } take a soda from machine add one soda to machine signal (hasRorS) signal (hasRorS) unlock (sodaLock) unlock (sodaLock) } } How can we make the one CV soluOon work? Variations: one CV? consumer () { producer () { lock (sodaLock) lock (sodaLock) while (numSodas == 0) { while(numSodas==MaxSodas){ wait (sodaLock,hasRorS) wait (sodaLock,hasRorS) } } take a soda from machine add one soda to machine broadcast (hasRorS) broadcast (hasRorS) unlock (sodaLock) unlock (sodaLock) } } Use broadcast instead of signal: safe but slow. Broadcast vs signal ê Can I always use broadcast instead of signal? ê Yes, assuming threads recheck condition ê And they should: “loop before you leap”! ê Mesa semantics requires it anyway: another thread could get to the lock before wait returns. ê Why might I use signal instead? ê Efficiency (spurious wakeups) ê May wakeup threads for no good reason ê “Signal is just a performance hint”. lpcox slide edited by chase Locking a critical section The threads may run the critical section in either order, but the schedule can never mx->Acquire(); enter the grey region where both threads load execute the section at the same time. add x = x + 1; store mx->Release(); þ R x=x+1 load mx->Acquire(); add x = x + 1; A store mx->Release(); x=x+1 A R Holding a shared mutex prevents competing threads from entering a critical section protected by the shared mutex (monitor). At most one thread runs in the critical section at a time. Locking a critical section load 3. add store load mx->Acquire(); load þ add x = x + 1; add store mx->Release(); store load add 4. store synchronized mx->Acquire(); serialized load add x = x + 1; load þ atomic store add mx->Release(); store Holding a shared mutex prevents competing threads from entering a critical section. If the critical section code acquires the mutex, then its execution is serialized: only one thread runs it at a time. How about this? load add x = x + 1; A store load mx->Acquire(); add x = x + 1; B store mx->Release(); How about this? load add x = x + 1; A store The locking discipline is not followed: purple fails to acquire the lock mx. load mx->Acquire(); Or rather: purple accesses the variable add x = x + 1; B x through another program section A store that is mutually critical with B, but does mx->Release(); not acquire the mutex. A locking scheme is a convention that the entire program must follow. How about this? load lock->Acquire(); add x = x + 1; store A lock->Release(); load mx->Acquire(); add x = x + 1; B store mx->Release(); How about this? load lock->Acquire(); add x = x + 1; store A lock->Release(); This guy is not acquiring the right lock. Or whatever. They’re not using the load mx->Acquire(); same lock, and that’s what matters. add x = x + 1; B store A locking scheme is a convention that mx->Release(); the entire program must follow. Ucontext library routines • The system can use ucontext routines to: – “Freeze” at a point in time of the execution – Restart execution from a frozen moment in time – Execution continues where it left off…if the memory state is right. • The system can implement multiple independent threads of execution within the same address space. – Create a context for a new thread with makecontext: when switched in it will call a specified procedure with specified arg. – Modify saved contexts at will. – Context switch with swapcontext: transfer a core from one thread to another Messing with the context #include <ucontext.h> ucontext Standard C library routines to: int count = 0; ucontext_t context; Save current register context to a block of memory (getcontext from core) int main() { Load/restore current register context int i = 0; from a block of memory (setcontext) getcontext(&context); Also: makecontext, swapcontext count += 1; i += 1; Details of the saved context (ucontext_t sleep(2); structure) are machine-dependent. printf(”…", count, i); setcontext(&context); } Messing with the context (2) #include <ucontext.h> int count = 0; ucontext_t context; Save CPU core context to memory int main() { Loading the saved context int i = 0; transfers control to this block getcontext(&context); of code. (Why?) count += 1; What about the stack? i += 1; sleep(1); printf(”…", count, i); Load core context from memory setcontext(&context); } Messing with the context (3) #include <ucontext.h> int count = 0; chase$ cc -o context0 context0.c ucontext_t context; < warnings: int main() ucontext deprecated on MacOS { > int i = 0; chase$ ./context0 getcontext(&context); 1 1 2 2 count += 1; 3 3 i += 1; 4 4 sleep(1); 5 5 printf(”…", count, i); 6 6 7 7 setcontext(&context); … } Reading behind the C count += 1; On MacOS: chase$ man otool i += 1; chase$ otool –vt context0 … Disassembled code: On this machine, with this cc: movl 0x0000017a(%rip),%ecx Static global _count is addressed addl $0x00000001,%ecx relative to the location of the code movl %ecx,0x0000016e(%rip) itself, as given by the PC register [%rip is instruction pointer register] movl 0xfc(%rbp),%ecx Local variable i is addressed as an addl $0x00000001,%ecx offset from stack frame. movl %ecx,0xfc(%rbp) [%rbp is stack frame base pointer] %rip and %rbp are set “right”, then these references “work”. Messing with the context (4) #include <ucontext.h> int count = 0; chase$ cc –O2 -o context0 context0.c ucontext_t context; < warnings: int main() ucontext deprecated on MacOS { > int i = 0; chase$ ./context0 getcontext(&context); 1 1 2 1 count += 1; 3 1 i += 1; 4 1 sleep(1); 5 1 printf(”…", count, i); 6 1 7 1 setcontext(&context); … What happened? } Messing with the context (5) #include <ucontext.h> int count = 0; ucontext_t context; int main() { int i = 0; getcontext(&context); count += 1; What does this do? i += 1; sleep(1); printf(”…", count, i); setcontext(&context); } .

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    31 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us