cps 310 threads and concurrency topics
play

CPS 310 Threads and Concurrency: Topics Jeff Chase Duke - PowerPoint PPT Presentation

D D u k e S y s t t e m s CPS 310 Threads and Concurrency: Topics Jeff Chase Duke University h>p://www.cs.duke.edu/~chase/cps310 Terminology and syntax The abstractions for


  1. D D u k e S y s t t e m s CPS ¡310 ¡ Threads ¡and ¡Concurrency: ¡Topics ¡ Jeff ¡Chase ¡ Duke ¡University ¡ ¡ h>p://www.cs.duke.edu/~chase/cps310 ¡

  2. 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.

  3. Example: the soda/HFCS machine Soda ¡drinker ¡ (consumer) ¡ Delivery ¡person ¡ (producer) ¡ Vending ¡machine ¡ (buffer) ¡

  4. Producer-consumer code consumer () { producer () { take a soda from machine add one soda to machine } }

  5. 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)

  6. Producer-consumer code consumer () { producer () { lock lock take a soda from machine add one soda to machine unlock unlock } }

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

  8. 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) CV1 ¡ CV2 ¡ unlock (sodaLock) unlock (sodaLock) } }

  9. 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(); } }

  10. Producer-consumer code consumer () { synchronized(o) { while (numSodas == 0) { o.wait () } take a soda o.notify(); } }

  11. 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 ¡mulOple ¡consumers. ¡ ¡ lpcox slide edited by chase

  12. 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) }

  13. 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) }

  14. 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? ¡

  15. 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 ¡waiOng? ¡ ¡ ¡max=1, ¡cA ¡and ¡cB ¡wait, ¡pC ¡adds/signals, ¡pD ¡waits, ¡cA ¡wakes ¡

  16. 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? ¡

  17. 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. ¡

  18. 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

  19. Locking a critical section The threads may run the critical section in either order, but the schedule can never enter the grey region where both threads mx->Acquire(); load execute the section at the same time. x = x + 1; add store mx->Release(); þ þ R x=x+1 mx->Acquire(); load A x = x + 1; add 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.

  20. Locking a critical section load add 3. store þ þ mx->Acquire(); load load add x = x + 1; add store store mx->Release(); load add þ þ 4. store synchronized mx->Acquire(); load serialized load x = x + 1; add 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.

  21. How about this? load A x = x + 1; add store mx->Acquire(); load x = x + 1; B add store mx->Release();

  22. How about this? load A x = x + 1; add store The locking discipline is not followed: purple fails to acquire the lock mx. mx->Acquire(); load Or rather: purple accesses the variable x = x + 1; B add store x through another program section A mx->Release(); that is mutually critical with B , but does not acquire the mutex. A locking scheme is a convention that the entire program must follow.

  23. How about this? lock->Acquire(); load add x = x + 1; A store lock->Release(); mx->Acquire(); load x = x + 1; B add store mx->Release();

  24. How about this? lock->Acquire(); load add x = x + 1; A store lock->Release(); This guy is not acquiring the right lock. Or whatever. They’re not using the mx->Acquire(); load same lock, and that’s what matters. x = x + 1; B add store mx->Release(); A locking scheme is a convention that the entire program must follow.

  25. 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

  26. 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); }

Recommend


More recommend