1 / 120

Chapter 6, Process Synchronization, Overheads, Part 2

Chapter 6, Process Synchronization, Overheads, Part 2. The second half of Chapter 6, Part 2, consists of these sections 6.7 Monitors 6.8 Java Synchronization. 6.7 Monitors. Monitors are an important topic for two reasons

kyria
Download Presentation

Chapter 6, Process Synchronization, Overheads, Part 2

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chapter 6, Process Synchronization, Overheads, Part 2

  2. The second half of Chapter 6, Part 2, consists of these sections • 6.7 Monitors • 6.8 Java Synchronization

  3. 6.7 Monitors • Monitors are an important topic for two reasons • As seen, the use of semaphores is fraught with difficulty, so overall, monitors might be a better concept to learn • Monitors are worth understanding because Java synchronization is ultimately built on this more general construct

  4. A high level, O-O description of what a monitor is: • It’s a class with (private) instance variables and (public) methods • Mutual exclusion is enforced over all of the methods at the same time

  5. This means that no two threads can be in any of the methods at the same time • In other words, all of the code belonging to the class is one giant critical section • Because a monitor has mutual exclusion over all methods, there is no need for separate acquire() and release() methods

  6. The private instance variables (possibly >1) of a monitor, which in some sense may be thought of as locks or perhaps shared resources, are completely protected by definition • There is no access to them except through the methods, and all of the methods have mutual exclusion enforced on them

  7. The relationship of monitors to Java • In Java there is a Monitor class, but that is just something made available in the API • The monitor concept is a fundamental part of the structure and design of Java • It is the monitor concept, not the Monitor class, that is the basis for all synchronization in Java

  8. The Object class in Java is the source of certain monitor (concept) methods that are available to its subclasses • Java also has a Condition interface which corresponds to what is called a condition variable in the monitor concept • The condition variable in a monitor is roughly analogous to the lock variable inside a semaphore

  9. The entry set for a monitor • After one thread has entered one method of a monitor, others may be scheduled and attempt to enter the critical section. • The monitor has what is known as an entry set. • It is essentially a scheduling queue for threads that want to get into the critical section.

  10. Condition Variables (or Objects) in Monitors • A monitor class can have Condition variables declared in it: • private Condition x, y; • A monitor class will also have two special methods: • wait() and signal()

  11. In order to understand how these methods work, it’s helpful to have a concrete scenario • Let there be two threads (or processes) P and Q • Let those threads share a reference to a monitor object, m • Let the monitor, m, have a condition variable x and a method monitorMethod()

  12. Both P and Q have the ability to call m.monitorMethod()—but because m is a monitor, only one of P or Q can be running in the code monitorMethod() at a time • Suppose that it was within code for Q that the call to m.monitorMethod() was called • Inside the code for monitorMethod() there may be a call • x.wait();

  13. When the thread that was “running in the monitor” calls x.wait(), the thread suspended • In this scenario, the thread Q, which was the thread which made the call on the monitor object, m, is suspended • Once it is suspended, it is no longer in the monitor

  14. If another thread makes a call to monitorMethod() (or any other monitor method) the new thread will be allowed into the monitor code • The original, suspended thread, Q, will remain suspended until another thread, such as P, is running monitor code which makes a call such as this: • x.signal()

  15. In a primitive semaphore, if a resource is not available, when a process calls acquire() and fails, the process goes into a spinlock • The logic of wait() improves on this • A process can voluntarily step aside by calling x.wait() • This allows another thread into the protected code

  16. wait() can be thought of as a tool that makes it possible for a process to take actions which affect its own execution order • It may be helpful to remember the concept of “politeness” that came up in the Alphonse and Gaston phase of trying to explain concurrency control when considering what wait() does • Making a wait() call allows other threads to go first

  17. Monitors and waiting lists • The thread that made the original x.wait() call voluntarily stepped aside • It goes into the waiting list • When another thread makes a call x.signal(), the thread making the signal() call is voluntarily() stepping aside and one in the waiting list will be resumed

  18. Let this scenario be given: • Thread Q is waiting because it earlier called x.wait() • Thread P is running and it calls x.signal() • By definition, only one of P and Q can be running in the monitor at the same time

  19. What protocol should be used to allow Q to begin running in the monitor instead of P? • This question is not one that has to be answered by the application programmer • It is a question that confronts the designer of a particular monitor implementation

  20. In general, there are two alternatives: • Signal and wait: • P signals, and its call to signal() implicitly includes a call to wait(), which allows Q to take its turn immediately. • After Q finishes, P resumes.

  21. Signal and continue: • P signals and continues until it leaves the monitor. • At that point Q can enter the monitor (or potentially may not, if prevented by some other condition) • In other words, P does not immediately leave the monitor, and Q does not immediately enter it

  22. It would be possible to make calls to wait() on any of the potentially many condition variables in a monitor, x, y, etc. • Each of the condition variables would have its own waiting list. • These separate waiting lists are distinct from the entry set, which contains the threads waiting to enter the critical section for the first time

  23. Monitors and the Dining Philosophers • The book next tries to illustrate the use of monitors in order to solve the dining philosophers problem • I am not going to cover this

  24. 6.8 Java Synchronization

  25. The term thread safe • Term: • Thread safe. • Definition: • Concurrent threads have been implemented so that they leave shared data in a consistent state

  26. Note: • Much of the example code shown previously would not be thread safe. • It is highly likely that threaded code without the use of synchronization syntax would generate a compiler error or warning indicating that it was not thread safe

  27. The most recent book examples, which used a semaphore class which did use the Java synchronization syntax internally, should not generate this error/warning • If code does produce this as a warning only, meaning that the code can still be run, it should be made emphatically clear that even though it runs, it IS NOT THREAD SAFE

  28. In other words, unsafe code may appear to run • More accurately it may run and even give correct results some or most of the time • But depending on the vagaries of thread scheduling, at completely unpredictable times, it will give incorrect results • This idea was discussed in some detail earlier

  29. Preliminaries • Keep in mind that the Java API supports synchronization syntax at the programmer level • This is based on monitor concepts built into Java • However, all synchronization ultimately is provided by something like a test and set instruction at the hardware level of the system that Java is running on

  30. Spin locks • The basic idea of a spin lock is that if one thread holds a resource, another thread wanting that resource will have to wait in some fashion • In the illustrative, application level pseudo-code, this waiting took the form of sitting in a loop

  31. Livelock • Spinlocks are wasteful and they can lead to livelock • Livelock is not quite the same as deadlock • In deadlock, two threads “can’t move” because each is waiting for an action that only the other can take • In livelock, both threads are alive and scheduled, but they still don’t make any progress

  32. The book suggests this bounded buffer scenario: • A producer has higher priority than a consumer • The producer fills the shared buffer • The producer remains alive, continuing to try and enter items into the buffer

  33. The consumer is alive, but having lower priority, it is never scheduled, so it can never remove a message from the buffer • Thus, the producer can never enter a new message into the buffer • The consumer can never remove one • But they’re both alive, the producer frantically so, and the consumer slothfully so

  34. Deadlock • Using real syntax that correctly enforces mutual exclusion can lead to deadlock • Deadlock is a real problem in the development of synchronized code, but it is not literally a problem of synchronization syntax • In other words, you can write an example that synchronizes correctly but still has this problem

  35. Java synchronization in two steps • The book takes the introduction of synchronization syntax through two stages: • Stage 1: You use Java synchronization and the Thread class yield() method to write code that enforces mutual exclusion and which is essentially a correct implementation of busy waiting. • This is wasteful and livelock prone, but it is synchronized

  36. Stage 2: You use Java synchronization with the wait(), notify(), and notifyAll() methods of the Object class. • Instead of busy waiting, this relies on the underlying monitor-like capabilities of Java to have threads wait in queues or lists. • This is deadlock prone, but it deals with the wastefulness of spin locks and the potential, however obscure, for live lock

  37. The synchronized Keyword in Java • Java synchronization is based on the monitor concept, and this descends all the way from the Object class • Every object in Java has a lock associated with it • This lock is essentially like a simple monitor, or a monitor with just one condition variable • Locking for the object is based on the single condition variable

  38. If you are not writing synchronized code—if you are not using the keyword synchronized— the object’s lock is completely immaterial • It is a system supplied feature of the object which lurks in the background unused by you and having no effect on what you are doing

  39. In the monitor concept, mutual exclusion is enforced on all of the methods of a class at the same time • Java is finer-grained. • Inside the code of a class, some methods can be declared synchronized and some can be unsynchronized

  40. However, if >1 method is declared synchronized in a class, then mutual exclusion is enforced across all of those methods at the same time for any threads trying to access the object • If a method is synchronized and no thread holds the lock, the first thread that calls the method acquires the lock

  41. Again, Java synchronization is monitor-like. • There is an entry set for the lock • If another thread calls a synchronized method and cannot acquire the lock, it is put into the entry set for that lock • The entry set is a kind of waiting list, but it is not called a waiting list because that term is reserved for something else

  42. When the thread holding the lock finishes running whatever synchronized method it was in, it releases the lock • At that point, if the entry set has threads in it, the JVM will schedule one • FIFO scheduling may be done on the entry set, but the Java specifications don’t require it

  43. The first correctly synchronized snippets of sample code which the book offers will be given soon • They do mutual exclusion on a shared buffer • They accomplish this by using the Thread class yield() method to do busy waiting

  44. The Java API simply says this about the yield() method: • “Causes the currently executing thread object to temporarily pause and allow other threads to execute.” • We don’t know how long the yield lasts, exactly • The important point is that it lasts long enough for another thread to be scheduled, if there is one that wants to be scheduled

  45. The book doesn’t bother to give a complete set of classes for this solution because it is not a very good one • Because it implements a kind of busy waiting, it’s wasteful, livelock prone, and deadlock prone • However, it’s worth asking what it illustrates that previous example didn’t • After the code on the following overheads additional comments will be made

  46. Synchronized insert() and remove() Methods for Producers and Consumers of a Bounded Buffer • public synchronized void insert(Object item) • { • while(count == BUFFER_SIZE) • Thread.yield(); • ++count; • buffer[in] = item; • in = (in + 1) % BUFFER_SIZE; • }

  47. public synchronized Object remove() • { • Object item; • while(count == 0) • Thread.yield(); • --count; • item = buffer[out]; • out = (out + 1) % BUFFER_SIZE; • return item; • }

  48. In previous illustrations we showed spin locks which were pure busy waiting loops • They had nothing in their bodies • If a thread in one method was spinning, you would probably hope that another thread could run in the complementary method • But the other thread would be locked out, due to synchronization • You could literally make no progress at all

  49. In this latest code, both methods are synchronized—effectively on the same lock • On the surface, you might think that you haven’t gained anything compared to the previous examples • What is added by making calls to yield() in the bodies of the loops?

  50. With a call to yield(), a thread is suspended • We don’t exactly know “where it goes to” when it’s suspended, but it is no longer “in” the synchronized code. • We also don’t know how long it will remain suspended, but the purpose is to remain suspended long enough for another thread to be scheduled

More Related