Presentation is loading. Please wait.

Presentation is loading. Please wait.

Background Concurrent access to shared data may result in data inconsistency Maintaining data consistency requires mechanisms to ensure the orderly execution.

Similar presentations


Presentation on theme: "Background Concurrent access to shared data may result in data inconsistency Maintaining data consistency requires mechanisms to ensure the orderly execution."— Presentation transcript:

1

2 Background Concurrent access to shared data may result in data inconsistency Maintaining data consistency requires mechanisms to ensure the orderly execution of cooperating processes Suppose that we wanted to provide a solution to the consumer-producer problem that fills all the buffers. We can do so by having an integer count that keeps track of the number of full buffers. Initially, count is set to 0. It is incremented by the producer after it produces a new buffer and is decremented by the consumer after it consumes a buffer. /* producer code */ while (count = BUFFER_SIZE) ; // do nothing //add an item to the buffer buffer[in] = item; in = (in + 1) % BUFFER_SIZE; count++; /* producer code */ while (count = BUFFER_SIZE) ; // do nothing //add an item to the buffer buffer[in] = item; in = (in + 1) % BUFFER_SIZE; count++; /* consumer code */ while (count = 0) ; // do nothing //add an item to the buffer item = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--; /* consumer code */ while (count = 0) ; // do nothing //add an item to the buffer item = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--;

3 Implementation count++ could be implemented as: register1 = count register1 = register1 + 1 count = register 1 count-- could be implemented as: register2 = count register2 = register2 – 1 count = register 2 Consider this executing interleaving with count = 5 initially: 1.producer executesregister1 = count(register1 = 5) 2.producer executesregister1 = register1 + 1 (register1 = 6) 3.consumer executesregister2 = count(register2 = 5) 4.consumer executesregister2 = register2 – 1 (register2 = 4) 5.producer executescount = register1(count = 6) 6.consumer executescount = register2(count = 4) This creates a race condition.

4 Critical Section Suppose we have n processes: P 0, P 1, …, P n Each process has a segment of code, called a critical section, in which the process changes shared memory If one process is executing in its critical section, no other process ought to execute in its critical section Critical-Section Problem: design a protocol to facilitate process communication and protect shared resources /* typical process structure */ while (true) { entry section critical section exit section remainder section } /* typical process structure */ while (true) { entry section critical section exit section remainder section } Standard design: 1.Entry section: a process must request permission to enter critical section 2.Process executes critical section 3.Exit section: process notifies others that it has exited its critical section 4.Remainder section: any code following the critical section

5 Requirements A solution to the critical-section problem must satisfy: 1.Mutual Exclusion: If process P i is executing in its critical section, then no other processes can be executing in their critical sections. 2.Progress: If no process is executing in its critical section and there exist some processes that wish to enter their critical section, then the selection of the processes that will enter the critical section next cannot be postponed indefinitely. 3.Bounded Waiting: A bound must exist on the number of times that other processes are allowed to enter their critical sections after a process has made a request to enter its critical section and before that request is granted. Assume that each process executes at a nonzero speed No assumption concerning relative speed of the processes

6 Peterson’s Solution Works for two processes, denoted P 0 and P 1 Requires that machine-language load and store operations are atomic—that is, they cannot be interrupted The two processes share two data items: int turn; boolean flag[2]; Variable turn indicates whose turn it is to enter the critical section. Array flag indicates whether each process is ready to enter its critical section. If flag[i] = true, then P i is ready.

7 Peterson’s Solution Examine the code to see that this satisfies the three requirements: 1.Mutual exclusion 2.Progress 3.Bounded Waiting while (true) { flag[i] = true; turn = j; while (flag[j] && turn == j) /* wait */ ; critical section flag[i] = false; remainder section } while (true) { flag[i] = true; turn = j; while (flag[j] && turn == j) /* wait */ ; critical section flag[i] = false; remainder section }

8 Locks We can prevent race conditions by protecting critical section with locks. A process must acquire a lock before entering its critical section. A process releases a lock when it exits its critical section. Locks may be implemented in software or hardware. /* solution using locks */ while (true) { acquire lock critical section release lock remainder section } /* solution using locks */ while (true) { acquire lock critical section release lock remainder section }

9 Hardware Solutions Many systems provide hardware support for critical section code. On a single-processor system, we could disable interrupts when a process executes its critical section. – Currently running code would execute without preemption – Generally too inefficient on multiprocessor systems – Operating systems using this not broadly scalable Modern machines provide special atomic (non-interruptible) hardware instructions. For example: – Test memory word and set value – Swap contents of two memory words Java HardwareData class presents an abstract view of atomic hardware instructions

10 Java HardwareData /** * Sample data structure for hardware solution * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.4 */ public class HardwareData { private boolean value = false; public HardwareData(boolean value) { this.value = value; } public boolean get() { return value; } public void set(boolean newValue) { this.value = newValue; } public boolean getAndSet(boolean newValue) { boolean oldValue = this.get(); this.set(newValue); return oldValue; } public void swap(HardwareData other) { boolean temp = this.get(); this.set(other.get()); other.set(temp); } /** * Sample data structure for hardware solution * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.4 */ public class HardwareData { private boolean value = false; public HardwareData(boolean value) { this.value = value; } public boolean get() { return value; } public void set(boolean newValue) { this.value = newValue; } public boolean getAndSet(boolean newValue) { boolean oldValue = this.get(); this.set(newValue); return oldValue; } public void swap(HardwareData other) { boolean temp = this.get(); this.set(other.get()); other.set(temp); } Each of these methods must be implemented atomically. /** * Using HardwareData getAndSet() to implement a lock * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.5 */ //lock is shared by all threads HardwareData lock = new HardwareData(false); while (true) { while (lock.getAndSet(true)) Thread.yield(); /* critical section */ lock.set(false); /* remainder section */ } /** * Using HardwareData getAndSet() to implement a lock * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.5 */ //lock is shared by all threads HardwareData lock = new HardwareData(false); while (true) { while (lock.getAndSet(true)) Thread.yield(); /* critical section */ lock.set(false); /* remainder section */ } /** * Using HardwareData swap() to implement a lock * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.6 */ //lock is shared by all threads HardwareData lock = new HardwareData(false); //each thread has a local copy of key HardwareData key = new HardwareData(true); while (true) { key.set (true); do { lock.swap(key); } while (key.get() == true); /* critical section */ lock.set(false); /* remainder section */ } /** * Using HardwareData swap() to implement a lock * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.6 */ //lock is shared by all threads HardwareData lock = new HardwareData(false); //each thread has a local copy of key HardwareData key = new HardwareData(true); while (true) { key.set (true); do { lock.swap(key); } while (key.get() == true); /* critical section */ lock.set(false); /* remainder section */ }

11 Semaphores Simpler synchronization tool than the previous A semaphore consists of: – an integer variable – atomic operations acquire() and release() The value of a counting semaphore can be any integer. The value of a binary semaphore (also called a mutex lock) is only 0 or 1. A binary semaphore can control access to a critical section. /* definitions of acquire() and release() */ acquire() { while value <= 0 ; // wait value--; } release() { value++; } /* definitions of acquire() and release() */ acquire() { while value <= 0 ; // wait value--; } release() { value++; } /* using a binary semaphore to control access to a critical section */ Semaphore sem = new Semaphore(1); sem.acquire(); /* critical section */ sem.release(); /* remainder section */ /* using a binary semaphore to control access to a critical section */ Semaphore sem = new Semaphore(1); sem.acquire(); /* critical section */ sem.release(); /* remainder section */

12 Multiple Java Threads using Semaphores /** * Worker thread to demonstrate use of a semaphore * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.8 */ public class Worker implements Runnable { private Semaphore sem; public Worker(Semaphore sem) { this.sem = sem; } public void run() { while (true) { sem.acquire(); criticalSection(); sem.release(); remainderSection(); } /** * Worker thread to demonstrate use of a semaphore * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.8 */ public class Worker implements Runnable { private Semaphore sem; public Worker(Semaphore sem) { this.sem = sem; } public void run() { while (true) { sem.acquire(); criticalSection(); sem.release(); remainderSection(); } /** * create a semaphore and five threads * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.8 */ public class SemaphoreFactory { public static void main(String args[]) { Semaphore sem = new Semaphore(1); Thread[] bees = new Thread[5]; for (int i = 0; i < 5; i++) bees[i] = new Thread(new Worker(sem)); for (int i = 0; i < 5; i++) bees[i].start(); } /** * create a semaphore and five threads * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.8 */ public class SemaphoreFactory { public static void main(String args[]) { Semaphore sem = new Semaphore(1); Thread[] bees = new Thread[5]; for (int i = 0; i < 5; i++) bees[i] = new Thread(new Worker(sem)); for (int i = 0; i < 5; i++) bees[i].start(); }

13 Semaphore Implementation Disadvantage of previous implementation: busy waiting Better idea: – When a process fails to acquire a semaphore, it places itself in a waiting queue associated with the semaphore. – When a process releases a semaphore, it restarts a process waiting for the semaphore. This requires a semaphore to be an integer value and a list of processes. Now value might be negative; if so, its magnitude is the number of waiting processes. /* definitions of acquire() and release() */ acquire() { value--; if (value <= 0) { add this process to list block(); } release() { value++; if (value < 0) { remove a process P from list wakeup(P); } /* definitions of acquire() and release() */ acquire() { value--; if (value <= 0) { add this process to list block(); } release() { value++; if (value < 0) { remove a process P from list wakeup(P); }

14 Semaphore Implementation Operating provides block() and wakeup(P) as basic system calls The list may be implemented as any type of queue. Important: acquire() and release() must be implemented atomically—this creates a critical section problem! We have transferred the critical section problem from the application program to the Semaphore class, but it’s progress, since the new critical sections are short. Possible solutions: – Disable interrupts during acquire() and release() – Use a hardware solution /* definitions of acquire() and release() */ acquire() { value--; if (value <= 0) { add this process to list block(); } release() { value++; if (value < 0) { remove a process P from list wakeup(P); } /* definitions of acquire() and release() */ acquire() { value--; if (value <= 0) { add this process to list block(); } release() { value++; if (value < 0) { remove a process P from list wakeup(P); }

15 Possible Problem: Deadlock

16 Possible Problem: Priority Inversion A high-priority process might have to wait for a low-priority process to release a shared resource. Example: – Three processes, L, M, and H, with priorities L < M < H – Process H is waiting for resource R, which is currently locked by process L – Process M becomes runnable and preempts process L – Now process M has caused process H to wait longer This problem is called priority inversion. Possible solutions: – Have only two priorities – Priority-inheritance protocol: all processes accessing resources needed by higher-priority processes inherit the higher priority until they release the resources

17 Bounded Buffer Problem Recall: BoundedBuffer helps solve the Producer-Consumer Problem We can use semaphores to protect the shared memory items in the BoundedBuffer object /** * bounded buffer with semaphores * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.9 */ import java.util.*; public class BoundedBuffer implements Buffer { private static final int BUFFER_SIZE = 5; private E[] buffer; private int in, out; private Semaphore mutex; private Semaphore empty; private Semaphore full; public BoundedBuffer() { // buffer is initially empty in = 0; out = 0; mutex = new Semaphore(1); empty = new Semaphore(BUFFER_SIZE); full = new Semaphore(0); buffer = (E[]) new Object[BUFFER_SIZE]; } public void insert(E item) {... } public void insert(E item) {... } /** * bounded buffer with semaphores * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.9 */ import java.util.*; public class BoundedBuffer implements Buffer { private static final int BUFFER_SIZE = 5; private E[] buffer; private int in, out; private Semaphore mutex; private Semaphore empty; private Semaphore full; public BoundedBuffer() { // buffer is initially empty in = 0; out = 0; mutex = new Semaphore(1); empty = new Semaphore(BUFFER_SIZE); full = new Semaphore(0); buffer = (E[]) new Object[BUFFER_SIZE]; } public void insert(E item) {... } public void insert(E item) {... } /* producers call this method */ public void insert(E item) { empty.acquire(); mutex.acquire(); // add an item to the buffer buffer[in] = item; in = (in + 1) % BUFFER_SIZE; mutex.release(); full.release(); } /* producers call this method */ public void insert(E item) { empty.acquire(); mutex.acquire(); // add an item to the buffer buffer[in] = item; in = (in + 1) % BUFFER_SIZE; mutex.release(); full.release(); } /* consumers call this method */ public void remove(E item) { E item; full.acquire(); mutex.acquire(); // remove an item to the buffer item = buffer[out]; out = (out + 1) % BUFFER_SIZE; mutex.release(); full.release(); return item; } /* consumers call this method */ public void remove(E item) { E item; full.acquire(); mutex.acquire(); // remove an item to the buffer item = buffer[out]; out = (out + 1) % BUFFER_SIZE; mutex.release(); full.release(); return item; }

18 Readers and Writers Problem Suppose several concurrent processes share access to a database. Some processes only read the database (call them readers), others read and write (call them writers). Readers-writers problem: We must ensure that writers have exclusive access to the shared database. Two variations: – First readers-writers problem: no reader should be kept waiting unless a writer has already obtained permission to use the database (writers might starve) – Second readers-writers problem: once a writer is ready, it must be able to write as soon as possible (readers might starve) The will examine a Java solution using semaphores.

19 Readers and Writers Problem /** * Database class, with methods to coordinate reader and writer * access to the database * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.18 */ public class Database implements ReadWriteLock { private int readerCount; // number of active readers Semaphore mutex; // controls access to readerCount Semaphore db; // controls access to the database public Database() { readerCount = 0; mutex = new Semaphore(1); db = new Semaphore(1); } public void acquireReadLock(int readerNum) { mutex.acquire(); /* first reader indicates that the database is being read */ ++readerCount; if (readerCount == 1) db.acquire(); mutex.release(); } public void releaseReadLock(int readerNum) { mutex.acquire(); /* last reader indicates database is no longer being read */ --readerCount; if (readerCount == 0) db.release(); mutex.release(); } public void acquireWriteLock(int writerNum) { db.acquire(); } public void releaseWriteLock(int writerNum) { db.release(); } /** * Database class, with methods to coordinate reader and writer * access to the database * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.18 */ public class Database implements ReadWriteLock { private int readerCount; // number of active readers Semaphore mutex; // controls access to readerCount Semaphore db; // controls access to the database public Database() { readerCount = 0; mutex = new Semaphore(1); db = new Semaphore(1); } public void acquireReadLock(int readerNum) { mutex.acquire(); /* first reader indicates that the database is being read */ ++readerCount; if (readerCount == 1) db.acquire(); mutex.release(); } public void releaseReadLock(int readerNum) { mutex.acquire(); /* last reader indicates database is no longer being read */ --readerCount; if (readerCount == 0) db.release(); mutex.release(); } public void acquireWriteLock(int writerNum) { db.acquire(); } public void releaseWriteLock(int writerNum) { db.release(); }

20 Dining Philosophers Problem Five philosophers sit around a circular table, with a single chopstick between each two philosophers. Philosophers alternate between thinking and eating. When a philosopher wants to eat, he first must pick up the two neighboring chopsticks, one after another. When a philosopher finishes eating, he returns the two chopsticks to the table. Problem: How can we prevent deadlock and starvation?

21 Dining Philosophers Problem Simple solution: represent each chopstick by a semaphore. This does not solve the possibility of deadlock. /* shared data (chopsticks) */ Semaphore chopStick[] = new Semaphore[5]; for(int i=0; i < 5; i++) chopStick[i] = new Semaphore(1); /* shared data (chopsticks) */ Semaphore chopStick[] = new Semaphore[5]; for(int i=0; i < 5; i++) chopStick[i] = new Semaphore(1); /* the structure of philosopher i */ while (true) { // get left chopstick chopStick[i].acquire(); // get right chopstick chopStick[(i+1)%5].acquire(); eating(); // return left chopstick chopStick[i].release(); // return right chopstick chopStick[(i+1)%5].release(); thinking(); } /* the structure of philosopher i */ while (true) { // get left chopstick chopStick[i].acquire(); // get right chopstick chopStick[(i+1)%5].acquire(); eating(); // return left chopstick chopStick[i].release(); // return right chopstick chopStick[(i+1)%5].release(); thinking(); } Possible solutions: – Allow at most four philosophers at the table – Allow a philosopher to pick up chopsticks only if both are available (must pick them up in a critical section) – Require odd philosophers to pick up left chopstick first, and even philosophers to pick up right chopstick first.

22 Problems with Semaphores If a single process is not well-behaved, then synchronization may fail. For example: semaphore.acquire(); critical section semaphore.release(); semaphore.acquire(); critical section semaphore.release(); critical section semaphore.acquire(); semaphore.release(); critical section semaphore.acquire(); critical section semaphore.acquire(); critical section semaphore.acquire(); //semaphore.acquire(); critical section semaphore.release(); //semaphore.acquire(); critical section semaphore.release(); Correct. violates mutual-exclusion requirement (error might not always occur) produces deadlock violates mutual-exclusion requirement

23 Monitors A monitor is an abstract type that controls access to a shared resource. The shared resource is only available via methods provided by the monitor. The monitor ensures that only one process at a time can access the shared resource. monitor monitor name { //shared variable declarations... //methods initialization code (...) {... } procedure P1 (...) {... } procedure P2 (...) {... }... } monitor monitor name { //shared variable declarations... //methods initialization code (...) {... } procedure P1 (...) {... } procedure P2 (...) {... }... }

24 Java Synchronization Java allows methods to be declared synchronized. Each Java object has an associated lock, which we have ignored until now, and which may be owned by a single thread. A thread acquires the lock for an object by calling a synchronized method of that object. – If no other thread owns the lock, then the calling thread gains ownership of the lock and runs the synchronized method. – If some thread owns the lock, then the calling thread waits in the entry set for the lock. When a thread exists a synchronized method, it releases the lock.

25 Synchronized BoundedBuffer /** * Implementing a bounded buffer with Java synchronization * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.27 */ public class BoundedBuffer { private static final int BUFFER_SIZE = 5; private int count; // number of items in the buffer private int in; // points to the next free position private int out; // points to the next full position private E[] buffer; // constructor public BoundedBuffer() {... } // Producers call this method public synchronized void insert(E item) { while (count == BUFFER_SIZE) Thread.yield(); buffer[in] = item; in = (in + 1) % BUFFER_SIZE; ++count; } // Consumers call this method public synchronized void remove(E item) { E item; while (count == 0) Thread.yield(); item = buffer[out]; out = (out + 1) % BUFFER_SIZE; --count; return item; } /** * Implementing a bounded buffer with Java synchronization * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.27 */ public class BoundedBuffer { private static final int BUFFER_SIZE = 5; private int count; // number of items in the buffer private int in; // points to the next free position private int out; // points to the next full position private E[] buffer; // constructor public BoundedBuffer() {... } // Producers call this method public synchronized void insert(E item) { while (count == BUFFER_SIZE) Thread.yield(); buffer[in] = item; in = (in + 1) % BUFFER_SIZE; ++count; } // Consumers call this method public synchronized void remove(E item) { E item; while (count == 0) Thread.yield(); item = buffer[out]; out = (out + 1) % BUFFER_SIZE; --count; return item; } Problem: Deadlock If the Producer tries to insert an item into a full buffer, it will sleep in the insert method and the Consumer will never be able to gain the lock to consume an item. Problem: Deadlock If the Producer tries to insert an item into a full buffer, it will sleep in the insert method and the Consumer will never be able to gain the lock to consume an item.

26 Java: Wait and Notify Each Java object also has a wait set. When a thread enters a synchronized method, it gains the lock for the object. If the thread determines that it has to wait for something, it can call the wait() method. When this happens: – The thread releases the lock for the object. – The state of the thread is set to blocked. – The thread is placed in the wait set for the object. The notify() method does the following: – Picks a thread T from the wait set – Moves T from the wait set to the entry set – Changes the state of T from blocked to runnable

27 Synchronized BoundedBuffer /** * Implementing a bounded buffer with Java synchronization * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.27 */ public class BoundedBuffer { private static final int BUFFER_SIZE = 5; private int count, in, out; private E[] buffer; // constructor public BoundedBuffer() {... } // Producers call this method public synchronized void insert(E item) { while (count == BUFFER_SIZE) { try { wait(); } catch (InterruptedException e) {} } buffer[in] = item; in = (in + 1) % BUFFER_SIZE; ++count; notify(); } // Consumers call this method public synchronized void remove(E item) { E item; while (count == 0) try { wait(); } catch (InterruptedException e) {} } item = buffer[out]; out = (out + 1) % BUFFER_SIZE; --count; notify(); return item; } /** * Implementing a bounded buffer with Java synchronization * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.27 */ public class BoundedBuffer { private static final int BUFFER_SIZE = 5; private int count, in, out; private E[] buffer; // constructor public BoundedBuffer() {... } // Producers call this method public synchronized void insert(E item) { while (count == BUFFER_SIZE) { try { wait(); } catch (InterruptedException e) {} } buffer[in] = item; in = (in + 1) % BUFFER_SIZE; ++count; notify(); } // Consumers call this method public synchronized void remove(E item) { E item; while (count == 0) try { wait(); } catch (InterruptedException e) {} } item = buffer[out]; out = (out + 1) % BUFFER_SIZE; --count; notify(); return item; }

28 Multiple Notification The notify() method selects an arbitrary thread from the wait set. It is possible that the selected thread is not, in fact, waiting on the condition for which it is notified. The notifyAll() method moves all threads from the wait set to the entry set. notifyAll() is a more expensive operation than notify(), but it is necessary if you must wake one particular thread out of many that might be sleeping

29 Java Synchronization Example Solving the Readers-Writers problem using Java synchronization… /** * Database class, with methods to coordinate reader and writer * access to the database using Java synchronization * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.33-6.35 */ public class Database implements ReadWriteLock { private int readerCount; // number of active readers private boolean dbWriting; // indicates whether databse is in use public Database() { readerCount = 0; dbWriting = false; } public synchronized void acquireReadLock() { while (dbWriting == true) { try { wait(); } catch (InterruptedException e) { } } ++readerCount; } public synchronized void releaseReadLock() { --readerCount; /* last reader indicates database is no longer being read */ if (readerCount == 0) notify(); //wake up a writer } public synchronized void acquireWriteLock() { while (readerCount > 0 || dbWriting == true) { try { wait(); } catch(InterrputedException e) { } } /* once there are no readers or writers, indicate that the database is in use */ dbWriting = true; } public synchronized void releaseWriteLock() { dbWriting = false; notifyAll(); //wake up all readers } /** * Database class, with methods to coordinate reader and writer * access to the database using Java synchronization * * @author Gagne, Galvin, Silberschatz * Operating System Concepts with Java, 8th Ed., Fig. 6.33-6.35 */ public class Database implements ReadWriteLock { private int readerCount; // number of active readers private boolean dbWriting; // indicates whether databse is in use public Database() { readerCount = 0; dbWriting = false; } public synchronized void acquireReadLock() { while (dbWriting == true) { try { wait(); } catch (InterruptedException e) { } } ++readerCount; } public synchronized void releaseReadLock() { --readerCount; /* last reader indicates database is no longer being read */ if (readerCount == 0) notify(); //wake up a writer } public synchronized void acquireWriteLock() { while (readerCount > 0 || dbWriting == true) { try { wait(); } catch(InterrputedException e) { } } /* once there are no readers or writers, indicate that the database is in use */ dbWriting = true; } public synchronized void releaseWriteLock() { dbWriting = false; notifyAll(); //wake up all readers }

30 Java Block Synchronization The amount of time between when a lock is acquired and when it released is called the scope of the lock. A synchronized method could be too large of a scope. Java allows blocks of code to be declared synchronized. Example: Object lock = new Object();... public void someMethod() { nonCriticalSection(); synchronized(lock) { criticalSection(); } remainderSection(); } Object lock = new Object();... public void someMethod() { nonCriticalSection(); synchronized(lock) { criticalSection(); } remainderSection(); }

31 Java Synchronization Notes A thread can nest synchronized method invocations for different objects in order to own multiple locks simulaneously. wait(), notify(), and notifyAll() may only be called from synchronized methods or blocks. wait() throws an InterrupedException if the interruption status of its thread is set—that is, if someone has called interrupt() for that thread

32 Synchronization in Java 5 ReentrantLock – like the synchronized statement, but with more features – Allows granting the lock to the longest-waiting thread Counting semaphores – controls access to a resource that may be simultaneously accessed by some fixed number of threads – provides acquire() and release() methods Condition variables – provide similar functionality to wait() and notify() – offer more flexibility for threads that must wait for specific conditions


Download ppt "Background Concurrent access to shared data may result in data inconsistency Maintaining data consistency requires mechanisms to ensure the orderly execution."

Similar presentations


Ads by Google