Lecture 21 – CS2110 – Fall 2010 RACE CONDITIONS AND SYNCHRONIZATION.

Slides:



Advertisements
Similar presentations
Operating Systems Semaphores II
Advertisements

Operating Systems: Monitors 1 Monitors (C.A.R. Hoare) higher level construct than semaphores a package of grouped procedures, variables and data i.e. object.
Ken Birman 1. Refresher: Dekers Algorithm Assumes two threads, numbered 0 and 1 CSEnter(int i) { int J = i^1; inside[i] = true; turn = J; while(inside[J]
Operating Systems Part III: Process Management (Process Synchronization)
– R 7 :: 1 – 0024 Spring 2010 Parallel Programming 0024 Recitation Week 7 Spring Semester 2010.
Practice Session 7 Synchronization Liveness Deadlock Starvation Livelock Guarded Methods Model Thread Timing Busy Wait Sleep and Check Wait and Notify.
Ch 7 B.
Silberschatz, Galvin and Gagne ©2007 Operating System Concepts with Java – 7 th Edition, Nov 15, 2006 Chapter 6 (a): Synchronization.
Chapter 6: Process Synchronization
Silberschatz, Galvin and Gagne ©2009 Operating System Concepts – 8 th Edition, Chapter 6: Process Synchronization.
Interprocess Communication
Monitors & Blocking Synchronization 1. Producers & Consumers Problem Two threads that communicate through a shared FIFO queue. These two threads can’t.
CMSC 330: Organization of Programming Languages Threads Classic Concurrency Problems.
COS 461 Fall 1997 Concurrent Programming u Traditional programs do one thing at a time. u Concurrent programs do several things at once. u Why do this?
CS 11 java track: lecture 7 This week: Web tutorial:
CS444/CS544 Operating Systems Synchronization 2/16/2006 Prof. Searleman
Threading Part 3 CS221 – 4/24/09. Teacher Survey Fill out the survey in next week’s lab You will be asked to assess: – The Course – The Teacher – The.
Avishai Wool lecture Introduction to Systems Programming Lecture 4 Inter-Process / Inter-Thread Communication.
Synchronization in Java Nelson Padua-Perez Bill Pugh Department of Computer Science University of Maryland, College Park.
Synchronization in Java Fawzi Emad Chau-Wen Tseng Department of Computer Science University of Maryland, College Park.
1 Sharing Objects – Ch. 3 Visibility What is the source of the issue? Volatile Dekker’s algorithm Publication and Escape Thread Confinement Immutability.
29-Jun-15 Java Concurrency. Definitions Parallel processes—two or more Threads are running simultaneously, on different cores (processors), in the same.
Race Conditions CS550 Operating Systems. Review So far, we have discussed Processes and Threads and talked about multithreading and MPI processes by example.
U NIVERSITY OF M ASSACHUSETTS, A MHERST Department of Computer Science Emery Berger University of Massachusetts, Amherst Operating Systems CMPSCI 377 Lecture.
Threads II. Review A thread is a single flow of control through a program Java is multithreaded—several threads may be executing “simultaneously” If you.
1 CSCD 330 Network Programming Lecture 13 More Client-Server Programming Sometime in 2014 Reading: References at end of Lecture.
CS4231 Parallel and Distributed Algorithms AY 2006/2007 Semester 2 Lecture 2 (19/01/2006) Instructor: Haifeng YU.
Java Threads. What is a Thread? A thread can be loosely defined as a separate stream of execution that takes place simultaneously with and independently.
COMP 111 Threads and concurrency Sept 28, Tufts University Computer Science2 Who is this guy? I am not Prof. Couch Obvious? Sam Guyer New assistant.
Operating Systems ECE344 Ashvin Goel ECE University of Toronto Mutual Exclusion.
Producer-Consumer Problem The problem describes two processes, the producer and the consumer, who share a common, fixed-size buffer used as a queue.bufferqueue.
4061 Session 21 (4/3). Today Thread Synchronization –Condition Variables –Monitors –Read-Write Locks.
CSC321 Concurrent Programming: §5 Monitors 1 Section 5 Monitors.
Deadlock Detection and Recovery
Advanced Concurrency Topics Nelson Padua-Perez Bill Pugh Department of Computer Science University of Maryland, College Park.
Threads Doing Several Things at Once. Threads n What are Threads? n Two Ways to Obtain a New Thread n The Lifecycle of a Thread n Four Kinds of Thread.
Monitors and Blocking Synchronization Dalia Cohn Alperovich Based on “The Art of Multiprocessor Programming” by Herlihy & Shavit, chapter 8.
1 Condition Variables CS 241 Prof. Brighten Godfrey March 16, 2012 University of Illinois.
Operating Systems CSE 411 CPU Management Dec Lecture Instructor: Bhuvan Urgaonkar.
COSC 3407: Operating Systems Lecture 9: Readers-Writers and Language Support for Synchronization.
Comunication&Synchronization threads 1 Programación Concurrente Benemérita Universidad Autónoma de Puebla Facultad de Ciencias de la Computación Comunicación.
THREADS & CONCURRENCY Lecture 22– CS2110 – Fall 2015.
CSCI1600: Embedded and Real Time Software Lecture 17: Concurrent Programming Steven Reiss, Fall 2015.
Lecture 23 – CS2110 – Fall 2015 RACE CONDITIONS & SYNCHRONIZATION.
Concurrent Programming in Java Based on Notes by J. Johns (based on Java in a Nutshell, Learning Java) Also Java Tutorial, Concurrent Programming in Java.
Lecture 5 Page 1 CS 111 Summer 2013 Bounded Buffers A higher level abstraction than shared domains or simple messages But not quite as high level as RPC.
NETW 3005 Monitors and Deadlocks. Reading For this lecture, you should have read Chapter 7. NETW3005 (Operating Systems) Lecture 06 - Deadlocks2.
Race Conditions & Synchronization
Race Conditions & Synchronization
Multithreading / Concurrency
Race Conditions and Synchronization
CS703 – Advanced Operating Systems
Background on the need for Synchronization
Threads and Concurrency in Java: Part 2
Synchronization Lecture 24 – Spring April 2018
Threads and Concurrency
Synchronization Lecture 23 – Fall 2017.
Synchronization Lecture 24 – Fall 2018.
Race Conditions and Synchronization
Multithreading.
Race Conditions & Synchronization
Producer-Consumer Problem
Shared Memory Programming
Synchronization Lecture 24 – Fall 2018.
Java Concurrency.
Java Concurrency.
Synchronization Lecture 24 – Fall 2018.
Software Engineering and Architecture
CSE 542: Operating Systems
Synchronization Lecture 24 – Fall 2018.
Presentation transcript:

Lecture 21 – CS2110 – Fall 2010 RACE CONDITIONS AND SYNCHRONIZATION

Reminder  A “race condition” arises if two threads try and share some data  One updates it and the other reads it, or both update the data  In such cases it is possible that we could see the data “in the middle” of being updated  A “race condition”: correctness depends on the update racing to completion without the reader managing to glimpse the in-progress update  Synchronization (aka mutual exclusion) solves this 2

Java Synchronization (Locking) 3 private Stack stack = new Stack (); public void doSomething() { synchronized (stack) { if (stack.isEmpty()) return; String s = stack.pop(); } //do something with s... } Put critical operations in a synchronized block The stack object acts as a lock Only one thread can own the lock at a time synchronized block

Java Synchronization (Locking) 4 public void doSomething() { synchronized (this) {... } public synchronized void doSomething() {... } You can lock on any object, including this is equivalent to

How locking works  Only one thread can “hold” a lock at a time  If several request the same lock, Java somehow decides which will get it  The lock is released when the thread leaves the synchronization block  synchronized(someObject) { protected code }  The protected code has a mutual exclusion guarantee: At most one thread can be in it  When released, some other thread can acquire the lock 5

Locks are associated with objects  Every Object has its own built-in lock  Just the same, some applications prefer to create special classes of objects to use just for locking  This is a stylistic decision and you should agree on it with your teammates or learn the company policy if you work at a company  Code is “thread safe” if it can handle multiple threads using it… otherwise it is “unsafe” 6

Visualizing deadlock 7 Process A Process B X Y A has a lock on X wants a lock on Y B has a lock on Y wants a lock on X

Deadlocks always involve cycles  They can include 2 or more threads or processes in a waiting cycle  Other properties:  The locks need to be mutually exclusive (no sharing of the objects being locked)  The application won’t give up and go away (no timer associated with the lock request)  There are no mechanisms for one thread to take locked resources away from another thread – no “preemption” 8 “... drop that mouse or you’ll be down to 8 lives”

Dealing with deadlocks  We recommend designing code to either  Acquire a lock, use it, then promptly release it, or ... acquire locks in some “fixed” order  Example, suppose that we have objects a, b, c,...  Now suppose that threads sometimes lock sets of objects but always do so in alphabetical order  Can a lock-wait cycle arise? ... without cycles, no deadlocks can occur! 9

Higher level abstractions  Locking is a very low-level way to deal with synchronization  Very nuts-and-bolts  So many programmers work with higher level concepts. Sort of like ADTs for synchronization  We’ll just look at one example today  There are many others; take cs4410 to learn more 10

A producer/consumer example  Thread A produces loaves of bread and puts them on a shelf with capacity K  For example, maybe K=10  Thread B consumes the loaves by taking them off the shelf  Thread A doesn’t want to overload the shelf  Thread B doesn’t wait to leave with empty arms 11 producer shelvesconsumer

Producer/Consumer example 12 class Bakery { int nLoaves = 0; // Current number of waiting loaves final int K = 10; // Shelf capacity public synchronized void produce() { while(nLoaves == K) this.wait(); // Wait until not full ++nLoaves; this.notifyall(); // Signal: shelf not empty } public synchronized void consume() { while(nLoaves == 0) this.wait(); // Wait until not empty --nLoaves; this.notifyall(); // Signal: shelf not full }

Things to notice  Wait needs to wait on the same object that you used for synchronizing (in our example, “this”, which is this instance of the Bakery)  Notify wakes up just one waiting thread, notifyall wakes all of them up  We used a while loop because we can’t predict exactly which thread will wake up “next” 13

Bounded Buffer  Here we take our producer/consumer and add a notion of passing something from the producer to the consumer  For example, producer generates strings  Consumer takes those and puts them into a file  Question: why would we do this?  Keeps the computer more steadily busy 14

Producer/Consumer example 15 class Bakery { int nLoaves = 0; // Current number of waiting loaves final int K = 10; // Shelf capacity public synchronized void produce() { while(nLoaves == K) this.wait(); // Wait until not full ++nLoaves; this.notifyall(); // Signal: shelf not empty } public synchronized void consume() { while(nLoaves == 0) this.wait(); // Wait until not empty --nLoaves; this.notifyall(); // Signal: shelf not full }

Bounded Buffer example 16 class BoundedBuffer { int putPtr = 0, getPtr = 0; // Next slot to use int available = 0; // Items currently available final int K = 10; // buffer capacity T[] buffer = new T[K]; public synchronized void produce(T item) { while(available == K) this.wait(); // Wait until not full buffer[putPtr++ % K] = item; ++available; this.notifyall(); // Signal: not empty } public synchronized T consume() { while(available == 0) this.wait(); // Wait until not empty --available; T item = buffer[getPtr++ % K]; this.notifyall(); // Signal: not full return item; }

Trickier example  Suppose we want to use locking in a BST  Goal: allow multiple threads to search the tree  But don’t want an insertion to cause a search thread to throw an exception 17

Code we’re given is unsafe 18 class BST { Object name; // Name of this node Object value; // Value of associated with that name BST left, right; // Children of this node // Constructor public void BST(Object who, Object what) { name = who; value = what; } // Returns value if found, else null public Object get(Object goal) { if(name.equals(goal)) return value; if(name.compareTo(goal) < 0) return left==null? null: left.get(goal); return right==null? null: right.get(goal); } // Updates value if name is already in the tree, else adds new BST node public void put(Object goal, object value) { if(name.equals(goal)) { this.value = value; return; } if(name.compareTo(goal) < 0) { if(left == null) { left = new BST(goal, value); return; } left.put(goal, value); } else { if(right == null) { right = new BST(goal, value); return; } right.put(goal, value); }

Attempt #1  Just make both put and get synchronized:  public synchronized Object get(…) { … }  public synchronized void put(…) { … }  Let’s have a look…. 19

Safe version: Attempt #1 20 class BST { Object name; // Name of this node Object value; // Value of associated with that name BST left, right; // Children of this node // Constructor public void BST(Object who, Object what) { name = who; value = what; } // Returns value if found, else null public synchronized Object get(Object goal) { if(name.equals(goal)) return value; if(name.compareTo(goal) < 0) return left==null? null: left.get(goal); return right==null? null: right.get(goal); } // Updates value if name is already in the tree, else adds new BST node public synchronized void put(Object goal, object value) { if(name.equals(goal)) { this.value = value; return; } if(name.compareTo(goal) < 0) { if(left == null) { left = new BST(goal, value); return; } left.put(goal, value); } else { if(right == null) { right = new BST(goal, value); return; } right.put(goal, value); }

Attempt #1  Just make both put and get synchronized:  public synchronized Object get(…) { … }  public synchronized void put(…) { … }  This works but it kills ALL concurrency  Only one thread can look at the tree at a time  Even if all the threads were doing “get”! 21

Visualizing attempt #1 22 Cathy cd4 Freddy netid: ff1 Martin mg8 Andy am7 Zelda za7 Darleen dd9 Ernie gb0 Put(Ernie, eb0) Get(Martin)… must wait! Get(Martin)… resumes

Attempt #2  put uses synchronized in method declaration  So it locks every node it visits  get tries to be fancy:  Actually this is identical to attempt 1! It only looks different but in fact is doing exactly the same thing 23 // Returns value if found, else null public Object get(Object goal) { synchronized(this) { if(name.equals(goal)) return value; if(name.compareTo(goal) < 0) return left==null? null: left.get(goal); return right==null? null: right.get(goal); }

Attempt #3  Risk: “get” (read-only) threads sometimes look at nodes without locks, but “put” always updates those same nodes.  According to JDK rules this is unsafe 24 // Returns value if found, else null public Object get(Object goal) { boolean checkLeft = false, checkRight = false; synchronized(this) { if(name.equals(goal)) return value; if(name.compareTo(goal) < 0) { if (left==null) return null; else checkLeft = true; } else { if(right==null) return null; else checkRight = true; } if (checkLeft) return left.get(goal); if (checkRight) return right.get(goal); /* Never executed but keeps Java happy */ return null; } relinquishes lock on this – next lines are “unprotected”

Attempt #4  This version is safe: only accesses the shared variables left and right while holding locks  In fact it should work (I think) 25 // Returns value if found, else null public Object get(Object goal) { BST checkLeft = null, checkRight = null; synchronized(this) { if(name.equals(goal)) return value; if(name.compareTo(goal) < 0) { if (left==null) return null; else checkLeft = left; } else { if(right==null) return null; else checkRight = right; } if (checkLeft != null) return checkleft.get(goal); if (checkRight != null) return checkright.get(goal); /* Never executed but keeps Java happy */ return null; }

Attempt #3 illustrates risks  The hardware itself actually needs us to use locking and attempt 3, although it looks right in Java, could actually malfunction in various ways  Issue: put updates several fields: parent.left (or parent.right) for its parent node this.left and this.right and this.name and this.value  When locking is used correctly, multicore hardware will correctly implement the updates  But if you look at values without locking, as we did in Attempt #3, hardware can behave oddly! 26

Why can hardware cause bugs?  Issue here is covered in cs3410 & cs4410  Problem is that the hardware was designed under the requirement that if threads contend to access shared memory, then readers and writers must use locks  Solutions #1 and #2 used locks and so they worked, but had no concurrency  Solution #3 violated the hardware rules and so you could see various kinds of garbage in the fields you access!  Solution #4 should be correct, but perhaps not optimally concurrent (doesn’t allow concurrency while even one “put” is active)  It’s hard to design concurrent data structures! 27

More tricky things to know about  Java has actual “lock” objects  They support lock/unlock operations  But it isn’t easy to use them correctly  Always need a try/finally structure 28 Lock someLock = new Lock(); try { someLock.lock(); do-stuff-that-needs-a-lock(); } finally { someLock.unlock(); }

More tricky things to know about  Needs try/finally  Complication: someLock.unlock() can only be called by same thread that called lock.  Advanced issue: If your code catches exceptions and the thread that called lock() might terminate, the lock can’t be released! It remains locked forever... bad news Lock someLock = new Lock(); try { someLock.lock(); do-stuff-that-needs-a-lock(); } finally { someLock.unlock(); }

More tricky things to know about  With priorities Java can be very annoying  ALWAYS runs higher priority threads before lower priority threads if scheduler must pick  The lower priority ones might never run at all  Consequence: risk of a “priority inversion”  High priority thread t1 is waiting for a lock, t2 has it  Thread t2 is runnable, but never gets scheduled because t3 is higher priority and “busy” 30

Debugging concurrent code  There are Eclipse features to help you debug concurrent code that uses locking  These include packages to detect race conditions or non-deterministic code paths  Packages that will track locks in use and print nice summaries if needed  Packages for analyzing performance issues Heavy locking can kill performance on multicore machines Basically, any sharing between threads on different cores is a performance disaster 31

Summary 32  Use of multiple processes and multiple threads within each process can exploit concurrency Which may be real (multicore) or “virtual” (an illusion)  But when using threads, beware! Must lock (synchronize) any shared memory to avoid non- determinism and race conditions Yet synchronization also creates risk of deadlocks Even with proper locking concurrent programs can have other problems such as “livelock”  Serious treatment of concurrency is a complex topic (covered in more detail in cs3410 and cs4410)  Nice tutorial at