Block2 Unit 5 IPC in Shared Memory Classical
Block-2 Unit 5: IPC in Shared Memory: Classical Problems and Language Primitives 1
Unit-5 • Three sections : • Section 1 : studying the use of semaphores to solve some classical problems in concurrency: – The producer–consumer problem – The bounded buffer problem; – The multiple readers, single writer problem. • Sections 2 and 3: studying high-level language structures for concurrency: – monitors (Section 2) – active objects and guarded commands (Section 3). 2
Section 1: use of semaphores in classical problems 3
Introduction • Two problems involving concurrent access to shared data are: – how to make a single operation on shared data atomic; – how to make these operations available to the programmer. • Different categories of process: readers, writers, producers and consumers of data. 4
The Producer-Consumer, bounded buffer Problem • Buffer: – A buffer is an area of storage capable of holding a number of data items shared by two or more processes. – A buffer is used to smooth out irregular bursts of activity by the processes. – It is also used to smooth out differences in the characteristics of processes in terms of the amount of data that each process can deal with at any one time. • Cyclic or Bounded Buffer: is a data structure with many of the characteristics of an array with some special properties: – – The index values range from 0 to n-1 Some slots are occupied by data items; others are empty. “in” cursor to indicate the first available empty slot. “out” cursor to indicate the next data item that can be taken from the buffer. • Initially, both in and out must point to the same slot 5
Implementation of circular array • To implement of circular array with 5 elements in Java : static final int Buffer. Size = 5; Object[] buffer = new Object[Buffer. Size]; together with two cursors: int in = 0; int out = 0; • The in cursors can be incremented by writing, for example: in = (in + 1) % Buffer. Size; • where % is the modulus operator (e. g. 8 % 5 = 3 and 10 % 5 = 0). 6
The Producer-Consumer, bounded buffer Problem • Two processes share a common, fixed-size buffer (a bounded buffer). – The producer, puts data into the buffer – The consumer, takes data out. • The problem is to synchronize the execution of producer and consumer processes – The producer can store data in buffer if empty space is available, it can not store data if buffer is full, it has to wait for the consumer – consumer can take data from buffer if buffer is not full, If buffer empty the consumer must wait for the producer 7
The Producer-Consumer, bounded buffer Problem Producer-Consumer outline one producer , one consumer 8
The Producer-Consumer, bounded buffer Problem • Producer-Consumer problem (one producer, one consumer) solution with Delay for synchronization 9
The Producer-Consumer, bounded buffer Problem, one producer, one consumer Solution Using Semaphores: • • Two semaphores are used: items and spaces. Items is initialized to 0 indicating there are no items. Spaces is initialized to Buffer. Size. Each time the producer inserts an item it executes items. sem. Signal(), incrementing the item resource count managed by the items semaphore. • Each time the consumer removes an item it executes spaces. sem. Signal(), incrementing the space resource count managed by the spaces semaphore. • When the buffer is empty the consumer will block on items. sem. Wait(). • When the buffer is full the producer will block on spaces. sem. Wait(). 10
The Producer-Consumer, bounded buffer Problem • Solution Outlined: (one producer, one consumer) 11
single producer, single consumer algorithm import Semaphore. *; public class Buffer { static final int Buffer. Size=5; Object [] buffer = new Object[Buffer. Size]; int in; int out; Semaphore items, spaces public Buffer() { in = 0; out = 0; items = new Semaphore. Implementation(0); spaces = new Semaphore. Implementation(Buff er. Size); public void insert (Object item) { spaces. sem. Wait(); buffer[in] = item; in = (in+1) % Buffer. Size; itmes. sem. Signal(); } public Object remove () { Object item; items. sem. Wait(); item = buffer[out]; out = (out+1) % Buffer. Size; spaces. sem. Signal(); return item; } 12
The Producer-Consumer, bounded buffer Problem • For a single consumer and single producer the buffer is not accessed under mutual exclusion since – they are accessing different parts of the buffer (i. e. using different pointers). • Therefore, in the single producer, single consumer problem the issue is synchronizing the actions of two processes) not of simultaneously accessing a shared data item. 13
The Producer-Consumer, bounded buffer Problem more than one producer or consumer: • With more than one producer the problem is – two or more producers might try to access the buffer concurrently, they will place their data in the same slot (denoted by “in”). Thus they must gain exclusive access to the buffer. • Mutual exclusion between producers is obtained by using another semaphore (named “guard”). 14
Multiple producers, single consumer algorithm import Semaphore. *; public class Buffer { static final int Buffer. Size=5; Object [] buffer = new Object[Buffer. Size]; int in; int out; Semaphore items, spaces, guard; public Buffer() { in = 0; out = 0; items = new Semaphore. Implementation(0 ); } spaces = new Semaphore. Implementation(Buffer. Size); guard = new Semaphore. Implementation(1); } public void insert (Object item) { spaces. sem. Wait(); guard. sem. Wait(); buffer[in] = item; in = (in+1) % Buffer. Size; guard. sem. Signal(); itmes. sem. Signal(); } public Object remove () { Object item; items. sem. Wait(); item = buffer[out]; out = (out+1) % Buffer. Size; spaces. sem. Signal(); return item; 15 }
Safety and Liveness Properties • A property of a program is an attribute that is true of every possible history of that program. • Two fundamental properties are: – Safety: A safety property asserts that nothing bad happens during execution. – Liveness: A Liveness property asserts that something good eventually happens. • In a sequential program – Safety==(final state is correct) – Liveness== (program terminates) • In concurrent systems: – Safety ==The need for mutual exclusion. – Liveness==Absence of deadlock (safety) • Liveness properties depend on fairness, which is concerned with guaranteeing that a process will get the chance to proceed regardless of how other processes behave. 16
The Multiple Reader, Single Writer Problem • Example: multiple processes reads from a single file, the file is written by a single process. • Reading a file does not change its contents and hence having concurrent processes read it won’t cause any problems. • Writing to a file changes its content and must only be done by a single process at a time. • Hence a shared resource (such as a file) can have multiple readers and a single writer. • one reader and one writer waiting to access the file which should be given priority? – We can usually adopt a scheme that a writer has priority since reader would want to have the most recent version of the file. – whenever there is a writer waiting, all further readers should be blocked until all writers finish their operations. 17
The Multiple Reader, Single Writer Problem • 4 Semaphores are required: – One semaphore is required to manage the readers and writers. – One semaphore is required to enforce exclusive access for writers. – Two semaphores are required to implement the priority scheme. 18
Some Limitations of Semaphores • It is not easy to remember which semaphore is associated with which data structure. • It is easy to forget to use sem. Wait() or sem. Signal(). • It is not possible to specify a set of semaphores as an argument list to a sem. Wait() operation. • The time for which a process is blocked on a semaphore is not limited. • A process might have some processing possible even if it requires a blocked resource. Z = x( block, it is from shared resources ) + y • Solution is to create a new (child) process to carry on with the processing while the original one waits for the resource. 19
Section 2: Language primitives for shared memory 20
Introduction • In this section – how concurrency and mutual exclusion problems are addressed in high-level programming languages. • For example, the compiler can enforce the restriction that shared data is only accessed from within a critical region • and that critical regions are entered and exited correctly. – The programmer has to specify which data is shared and which code constitutes a critical region. – two programming constructs are required: • a declaration that specifies which variables are to be shared; • an indication of the start and finish of a critical region. 21
Synchronization in JAVA • A method that is declared as synchronized cannot be executed by more than one process at any time. public synchronized void increment() { //only one thread can execute this at any time x = x + 1; } • if an object has more than one method declared as synchronized, then an attempt to execute any synchronized method will be delayed until the first synchronized method has been completed. • If one thread is executing a synchronized method and a second thread tries to execute any other synchronized method with the same object, the second thread will be halted until the first thread completes. 22
Critical Regions in Programming Languages • A critical region construct requires syntax such as the following: – Declaring a data type to be shared: shared Data. Type some. Shared. Data – A region declaration such as: region (some. Shared. Data) {…. } 23
Critical Regions in Programming Languages • For each shared data the compiler could create a semaphore (cr. Sem) and insert the following code: shared Data. Type some. Shared. Data // Here the compiler creates the cr. Sem semaphore : region (some. Shared. Data){ // compiler inserts cr. Sem. sem. Wait() : // compiler inserts cr. Sem. sem. Signal() } 24
Critical Regions in Programming Languages • Conditional Critical Region: is a critical region controlled by a condition. When the condition is true, the process may enter the critical region. • Several readers can access shared data at the same time. • Having several writers, and in order to ensure mutual exclusion we should implement a new boolean variable “writelock” to prevent more than one writer accessing the shared resource at the same time. 25
Critical Regions in Programming Languages • Example 26
Monitors • A monitor has the structure of an abstract data object. • In a monitor the shared data and the operations manipulating it are encapsulated. • Monitor operations are executed under mutual exclusion. • A critical region is replaced by a call to a monitor operation. • The monitor implementation must ensure that only one process is active in the monitor at any time. • Recall that programming concurrent systems requires both mutual exclusion and condition synchronization. • Condition synchronization is provided in most monitorbased systems by a new type of variable called a condition variable. • Condition variables are similar to semaphores (has a queue) but has no value (‘no state’). 27
Monitors • The wait() operation of condition variables always queues the executing process. • The signal() operation is defined as when there any waiting processes then one of them is freed. If there are no waiting processes there is no effect. • Having called a monitor operation, the process has exclusive access to the shared data. • If a process is blocked (using wait()), it must release the monitor lock (exclusive access) so that other processes can access the shared data. • The blocked process is queued on the condition variable. 28
Monitors 29
Java: Synchronization Overview • In Java separate threads are created as objects of type Thread. • A new process (or thread) is created by invoking the start method on that object. The process will then execute the run method of that object. • Threads in Java can be created in 2 ways: – class Thread 1 extends Thread – class Thread 1 implements Runnable • Every thread has a priority in the range 1 to 10, where 10 is the highest priority. • By default, a thread inherits the priority of its creator. The main method (from which, ultimately, all threads come into existence) has, by default, a priority of 5. • Priorities can be set using the method set. Priority, and the current priority can be discovered using get. Priority 30
Java: Synchronization Overview • Some methods from class Thread: start run Changes the Thread state to runnable and invokes run Changes the Thread state to running is. Alive Returns true if the Thread started and has not yet terminated sleep Sleeps for some milliseconds set. Priority Changes the priority of the Thread get. Priority Returns the current priority of the Thread 31
Java: Synchronization Overview • Java primitives: – synchronized, wait(), and notify() or notify. All(). • In Java the Object class has the methods wait, notify, and notify. All which are automatically inherited by all other classes. • Methods in Java can be declared as synchronized where only one client process at a time will be allowed to execute this method. • The term synchronized indicates where mutual exclusion locks must be acquired. • Within a synchronized method, wait causes the Thread executing it to become suspended and queued • While notify causes an arbitrary Thread to be removed from the queue and to wait for scheduling and resuming. • Threads have two additional methods: – interrupt(): interrupt the thread and change its state to runnable. – is. Interrupted() the object makes repeated calls to this 32 method to detect if it was interrupted or not.
Java: Critical Regions • synchronized methods access shared data under mutul execlusion • While a Thread is executing a synchronized method, other Thread will be in a wait set associated with that object. • An Object with one or more synchronized methods acts as a monitor. • non synchronized methods may be invoked by another process at the same time as a synchronized method is being executed. – Therefore, for an object to act as a monitor, the data accessed by its synchronized methods must not be accessed by its non-synchronized methods. 33
Java: Condition Synchronization • When a Thread is waiting on a condition, it will only be able to proceed when the condition changes. • Example: If a condition involves an empty buffer, then the condition changes when an element is added to the buffer. • A Thread waiting for an element to be added to the buffer is not running and hence must wait for other Threads to do the change and execute notify or notify. All. 34
Some further issues relating to monitors • A process should leave the monitor in a consistent state before executing a condition. wait(). – A process that update shared data must update the whole shared data before executing condition. wait. If it is blocked the whole data, data will be inconsistent – For example, if the indexes on a bounded buffer have been modified but the process blocks before the data in the buffer has been processed, the indexes will not indicate the true state of the buffer. The next process to enter the monitor will not be aware of the problem and will erroneously assume that the data is in a consistent state. 35
Section 3: Synchronization at the granularity of operations 36
Introduction • Accessing shared object using monitors may delay a process – A process will wait to enter the monitor. And will wait inside the monitor if the state of the shared data is inconsistent • An attractive idea is to allow an operation on an object to go ahead only if the object is in a state such that the operation can complete. – avoids the possibility of two waits – This can be achieved using active objects. 37
Active Objects • An Active Object is an object with an internally bound process. • An Active Object can be used to manage shared data, thus creating monitor like structure. • active object which manages shared data has associated process which must ensure that the shared data is manipulated correctly by or on behalf of the external sharing processes. the method – can be made aware of outstanding calls from clients and can control the scheduling of these calls by the runtime system (can implement condition synchronization at the granularity of operations). – Can execute operations on behalf of the clients. – Can execute some of the housekeeping tasks associated with operations, such as updating buffer pointers and counts. 38
- Slides: 38