You are on page 1of 4
138 Chapter 6 Synchronization Principles 4, It invokes wait on semaphore mutex to gain exclusive access to the buffer, which is its critical section. The producer will be suspended if the consumer has already gained access to the buffer by executing its own critical section. 5. It will be reactivated when the consumer releases mutual exclusion. 6. It executes the critical section, which involves inserting the data item into an empty slot of the buffer. 7. It releases mutual exclusive access to the buffer by invoking the signal of semaphore mutex. 8. It invokes signal of semaphore full; this increments the value of semaphore full and reactivates the consumer if it has been suspended to wait for a full slot. ‘As with the producer process, the statements in the pseudocode that define the con- sumer process are enclosed in an endless loop, which implies that the consumer process is a nonterminating process. The consumer follows a similar sequence of instructions using the three semaphores and executes the following sequence of steps: 1. It checks if there are any full slots by invoking wait on semaphore full. 2. If there is at least one full slot, it proceeds to the next statement; otherwise, it is blocked. 3. It attempts to gain exclusive access to the buffer by invoking wait on semaphore mutex. 4. It executes its critical section, which involves removing an item from a full slot. 5. It releases mutual exclusion by invoking signal on semaphore mutex. 6. It increments the number of empty slots by invoking signal on semaphore empty. 7. It consumes the data item. 6.6.2 Synchronization with Semaphores in Java The previous section explained how the semaphores provided by the OS are used as synchronization tools. ‘The Java programming language has facilities for defining and creating Java threads. One way to define a thread class is by extending (inheriting) the Java Thread library class. The body of a thread is normally coded in method run. After a thread object is created, method start of the thread needs to be invoked in order for the thread object to start executing its run method. A thread object can be assigned a priority, and this could influence the way the Java Virtual Machine (JVM) 6.6 Synchronization Case Studies 139 schedules the threads. Static variables are shared among the threads, and the access to shared variables and to other resources needs to be synchronized. ‘The Java language provides a mechanism for basic mutually exclusive access to shared resources. Each object is provided a lock, but the lock can be acquired by only one thread at a time. Appropriate methods of the shared object must have synchronized methods. When a thread invokes a synchronized method on a shared object, a lock is acquired on that object. All other threads must wait until the lock is released by the thread that holds it. A synchronized method is used to guarantee mutually exclusive access to a shared object by the various threads. Java includes the wait/notify mechanism to help synchronize Java threads. Two methods are provided in the language: wait and notify. The wait method suspends a process invoking this method and puts the thread into a waiting state. The notify method reactivates a thread from waiting and puts it back in the ready queue ‘A semaphore is an object that can be shared by several thread objects. It can be defined to have two synchronized methods, swait and signal. The semaphore object will also have an integer attribute, sen. A semaphore can be defined in Java as follows: class Semaphore { private int sem; u“ public synchronized void wait() { vhile ( sem <= 0) { try ¢ swait(); } catch (Exception e) { System.exit(0);}; } // end while sem--; // decrease value of sem 3// end swait a“ public synchronized void signal() ¢ sent+; notify; } // end signal “ // constructor public Semaphore ( int intval) { sen = intval; // initialize attribute sem } // end class Semaphore Assume that the producer and consumer processes are implemented as threads and the buffer is implemented as an array of size N. The producer is defined with the following class, which inherits the Java class Thread: 140 Chapter 6 Synchronization Principles public class Producer extends Thread { private Senaphore mutex; private Semaphore full, private Semaphore empty; public Producer (Semaphore m, Semaphore f, Semaphore 6) { mutex full = empty = 65 ¥ // end constructor public void run() { while (true) { [ produce an item ] enpty.wait(); // axe there any eapty slots? mutex.vait(); // acquire exclusive acc [ deposit an item into an empty slot of the buffer } mutex. signal (); // release mutual exclusion full.signalQ; // sncrenent full slots } // end while loop >} // end run } // end class Producer Ina similar manner, the consumer is defined by the following class, which inherits (extends) the Java class Thread: public class Consumer extends Thread { private Semaphore mute: private Semaphore full; private Semaphore empty; public Consumer (Semaphore m, Semaphore f, Semaphore e) { mutex = 9; full empty > // end constructor u“ public run() { while (true) full waitQ; // axe there any full slots? mutex.wait(); // acquire exclusive acc [ remove an item from a full slot of the buffer ] mutex. signal (); // release mutual exclusion empty.signal(); // imerenent empty slots ([ Consume data item ] } // end while loop > // end while > / end run } // end class Consuner 6,6 Synchronization Case Studies 141 The main class defines method main, which creates and initializes the semaphore objects, creates the two thread objects (producer and consumer objects), and starts execution of the thread objects: public class ProdconSync { static final int N= 100; // mumber of slots in buffer public static void main (String args(]) { Semaphore mutex = new Semaphore (1); Semaphore full = new Semaphore (0); Semaphore empty = new Sexaphore (N); Producer prod = new Producer (mutex, full, empty); Consumer cons = new Consumer (mutex, full, empty); > // end main > // end clase ProdconSync 6.6.3 Simulation Models of the Bounded-Buffer Problem ‘The basic simulation model of the bounded-buffer problem (producer-consumer prob- lem) includes five classes: (1) Semaphore, (2) Buffer, (3) Producer, (4) Consumer, and (3) Consprod. The model with graphics and animation includes additional classes for displaying the GUI and the animation. The models are implemented in Java with the PsimJ2 simulation package, and they are stored in the archive files: consprod. jar and consprodanim. jar. Class Semaphore is implemented with the PsimJ2 resource class Bin. The swait operation on this semaphore class is implemented with the take method of class Bin, and the signal operation is implemented with the give method of class Bin. In the model, semaphore mutex is an object of class Semaphore initialized to 1. ‘The two counting semaphores are also objects of class Semaphore. One object is called empty and is initialized to numSlots. The other object is called full and is initialized to zero, Class Buffer consists of an array of characters. The operations are put and get. The capacity of the buffer is a constant value, numSlots. The producer takes a finite time to produce an item before it deposits it into the buffer. This is a random period generated from an exponential distribution given a mean period for producing an item. In a similar manner, the consumer takes a random period to consume an item that it has taken from the buffer. Both processes execute their activities in an endless loop. Each process spends a random time executing its critical section. Figure 6.6 shows the graphical user interface (GUI) for a simulation run of the consumer-producer simulation model. The following input parameters can be set: © Simulation time interval © Average time interval that the producer takes to produce a data item

You might also like