Critical section problem from Operating Systems Concepts goes like this -
Consider a process with n threads and each one of them executes a piece of code which involves changing shared variables, updating a table, writing to a file etc. This piece of code needs to be guarded so that multiple threads don't enter it at the same time. This block of code is the critical section. The critical section problem is to design a protocol so that threads can co-operate.
In order to implement a critical section, we can use one of the OS synchronization primitives such as mutex or Semaphore. Java provides an implementation of Semaphore which is useful to implement critical section. A semaphore with one permit is a mutex. So the below declaration gives us a mutex in java.
Semaphore mutex = new Semaphore(1);
Now that we have a mutex, we can use it to enforce the requirements of a critical section. Essentially the thread that needs access to critical section would wait on the semaphore and whenever another thread relinquishes the control of Semaphore, it gets access to the critical section.
public class CriticalSection {
private static Semaphore mutex = new Semaphore(1);
public synchronized void waitCS() {
mutex.wait();
}
public synchronized void notifyCS() {
mutex.notify();
}
}
Well there's no fun implementing this Critical Section. We haven't added any new functionality on top of what's provided by Semaphore. We could as well use a Semaphore directly to achieve the above functionality instead of wrapping the semaphore inside another class and name it Critical Section.
So lets add some value to this implementation.
A critical section differs from a mutex in that it avoids unnecessary kernel transitions, making it a faster, efficient & light weight implementation of mutex. In the context of a critical section, kernel transitions happen during system calls for wait() & notify(). These transitions are expensive and need to be avoided.
We will use a variable to keep track of the number of threads waiting for access to critical section. When there are no threads waiting for access to Critical Section, we can safely skip system calls(wait() and notify()) and hence avoid kernel transitions.
public class CriticalSection {
private static Semaphore mutex = new Semaphore(1);
// 0 - no threads are waiting - uncontested CS
// > 1 - threads are waiting - contested CS
private static AtomicInteger counter = new AtomicInteger(0);
public synchronized void waitCS() {
while(counter.incrementAndGet() != 1) {
mutex.wait();
}
}
public synchronized void notifyCS() {
int count = counter.get();
counter.set(0);
while(count > 1) {
mutex.notify();
}
}
}
References - Silberschatz, Abraham, Greg Gagne, and Peter B. Galvin. Operating System Concepts, Seventh Edition. N.p.: John Wiley & Sons, 2004. Print.
Consider a process with n threads and each one of them executes a piece of code which involves changing shared variables, updating a table, writing to a file etc. This piece of code needs to be guarded so that multiple threads don't enter it at the same time. This block of code is the critical section. The critical section problem is to design a protocol so that threads can co-operate.
In order to implement a critical section, we can use one of the OS synchronization primitives such as mutex or Semaphore. Java provides an implementation of Semaphore which is useful to implement critical section. A semaphore with one permit is a mutex. So the below declaration gives us a mutex in java.
Semaphore mutex = new Semaphore(1);
Now that we have a mutex, we can use it to enforce the requirements of a critical section. Essentially the thread that needs access to critical section would wait on the semaphore and whenever another thread relinquishes the control of Semaphore, it gets access to the critical section.
public class CriticalSection {
private static Semaphore mutex = new Semaphore(1);
public synchronized void waitCS() {
mutex.wait();
}
public synchronized void notifyCS() {
mutex.notify();
}
}
Well there's no fun implementing this Critical Section. We haven't added any new functionality on top of what's provided by Semaphore. We could as well use a Semaphore directly to achieve the above functionality instead of wrapping the semaphore inside another class and name it Critical Section.
So lets add some value to this implementation.
A critical section differs from a mutex in that it avoids unnecessary kernel transitions, making it a faster, efficient & light weight implementation of mutex. In the context of a critical section, kernel transitions happen during system calls for wait() & notify(). These transitions are expensive and need to be avoided.
We will use a variable to keep track of the number of threads waiting for access to critical section. When there are no threads waiting for access to Critical Section, we can safely skip system calls(wait() and notify()) and hence avoid kernel transitions.
public class CriticalSection {
private static Semaphore mutex = new Semaphore(1);
// 0 - no threads are waiting - uncontested CS
// > 1 - threads are waiting - contested CS
private static AtomicInteger counter = new AtomicInteger(0);
public synchronized void waitCS() {
while(counter.incrementAndGet() != 1) {
mutex.wait();
}
}
public synchronized void notifyCS() {
int count = counter.get();
counter.set(0);
while(count > 1) {
mutex.notify();
}
}
}
References - Silberschatz, Abraham, Greg Gagne, and Peter B. Galvin. Operating System Concepts, Seventh Edition. N.p.: John Wiley & Sons, 2004. Print.
No comments:
Post a Comment