Class 11 CS 372H 23 February 2010 On the board ------------ 1. Last time 2. Concurrent programming practice 3. Discuss labs 4. Trade-offs and problems from locking --------------------------------------------------------------------------- 1. Last time --introduced monitors, semaphores --threading advice Birrell's article is great. But a lot of it is "for experts only". My advice is: --follow what we tell you in this course --as you gain experience, then move to the techniques that Birrell suggests --do not stray from either of these Always worry about correctness first --Only amateur programmers begin optimizing before they know where the performance problems are 2. practice with concurrent programming --will post example from prior mid-term. use it as practice --will work a different example here: --workers interact with a database --motivation: banking, airlines, etc. --readers never modify database --writers read and modify data --using only a single mutex lock would be overly restrictive. Instead, want --many readers at the same time --only one writer at a time --let's follow the concurrency advice from last time... 1. Getting started a. what are units of concurrency? [readers/writers] b. what are shared chunks of state? [database] c. what does the main function look like? read() check in -- wait until no writers access DB check out -- wake up waiting writer, if appropriate write() check in -- wait until no readers or writers access DB check out -- wake up waitin readers or writers 2. and 3. Synchronization constraints and objects --reader can access DB when no writers (condition: okToRead) --writer can access DB when no other readers or writers (condition: okToWrite) --only one thread manipulates shared variables at a time. NOTE: **this does not mean only one thread in the DB at a time** (mutex) 4. write the methods --inspiration required: int AR = 0; // active readers int AW = 0; // # active writers int WR = 0; // waiting readers int WW = 0; // waitin writers --see handout for the code --QUESTION: why not just hold the lock all the way through "Execute req"? (Answer: the whole point was to provide more concurrency, i.e., to move away from exclusive access.) --QUESTION: what if we had shared locks? The implementation of shared locks is given on the handout 3. discuss labs --start lab 4 early. you have enough time to do everything but not if you wait until just before it's due. good time management practice (budget the time). --survey feedback: lots of dissatisfaction with office hours and labs --office hours: we will adjust --regarding labs.... 4. Trade-offs and problems from locking Locking (in all its forms: mutexes, monitors, semaphores) raises many issues: A. performance B. performance v. complexity trade-off C. deadlock D. starvation E. priority inversion We'll discuss these today and next time: A. Performance (inherent problems) (i) cache line bounces (ii) fairness --ccNUMA issues mitigation: better locks --Futexes (next time) --MCS locks (next time) (iii) locking inherently reduces concurrency mitigation: more fine-grained locking --but fine-grained locking leads to the next issue B. Performance v complexity trade-off --one big lock is often not great for performance: only one CPU at a time can execute anywhere in your code. If your code is called a lot, this may reduce the performance of an expensive multiprocessor to that of a single CPU. --Perhaps locking at smaller granularity would get higher performance through more concurrency. --But how to best reduce lock granularity is a bit of an art. --But unfortunately leads to incorrect code --Example: imagine that every file in the file system is represented by a number, in a big table --You might inspect the file system code and notice that most operations use just one file or directory, leading you to have one lock per file --But then cross-directory operations, like path-name lookup and rename(), will need special attention to get the locking right. --Continue this example next time....