5TH Operating System Notes
5TH Operating System Notes
A solution to the critical-section problem must satisfy the following three requirements: 1. Mutual exclusion. If process P, 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 some processes wish to enter their critical sections, then only those processes that are not executing in their remainder sections can participate in the decision on which will enter its critical section next, and this selection cannot be postponed indefinitely. 3. Bounded waiting. There exists a bound, or limit, 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. We assume that each process is executing at a nonzero speed. However, we can make no assumption concerning the relative speed of the n processes. Two general approaches are used to handle critical sections in operating systems: (1) preemptive kernels and (2) nonpreemptive kernels. A preemptive kernel allows a process to be preempted while it is running in kernel mode. A nonpreemptive kernel does not allow a process running in kernel mode to be preempted; a kernel-mode process will run until it exits kernel mode, blocks, or voluntarily yields control of the CPU. Obviously, a nonpreemptive kernel is essentially free from race conditions on kernel data structures, as only one process is active in the kernel at a time. We cannot say the same about nonpreemptive kernels, so they
www.bookspar.com
To prove that this solution is correct, we need to show that: 1. Mutual exclusion is preserved. 2. The progress requirement is satisfied. 3. The bounded-waiting requirement is met. To prove property 1, we note that each Pi enters its critical section only if either flag[j] == false or turn == i. Also note that, if both processes can be executing in their critical sections at
www.bookspar.com
The TestAndSet () instruction can be defined as shown boolean TestAndSet(boolean *target) { boolean rv = *target; *target = TRUE; return rv; } The important characteristic is that this instruction is executed atomically. Thus, if two TestAndSet () instructions are executed simultaneously (each on a different CPU), they will be executed sequentially in some arbitrary order. If the machine supports the TestAndSet () instruction, then we can implement mutual exclusion by declaring a Boolean variable lock, initialized to false. The structure of process Pi is shown: do { while (TestAndSetLock(&lock)) ; // do nothing // critical section lock = FALSE; // remainder section }while (TRUE);
www.bookspar.com
www.bookspar.com
www.bookspar.com
www.bookspar.com
One simple solution is to represent each chopstick with a semaphore. A philosopher tries to grab a chopstick by executing a wait () operation on that semaphore; she releases her chopsticks by executing the signal () operation on the appropriate semaphores. Thus, the shared data are semaphore chopstick[5]; where all the elements of chopstick are initialized to 1. The structure of philosopher i is shown
4.7 MONITORS A type, or abstract data type, encapsulates private data with public methods to operate on that data. A monitor type presents a set of programmer-defined operations that are provided mutual exclusion within the monitor. The monitor type also contains the declaration of variables whose values define the state of an instance of that type, along with the bodies of procedures or functions that operate on those variables. The syntax of a monitor is shown:
www.bookspar.com
The representation of a monitor type cannot be used directly by the various processes. Thus, a procedure defined within a monitor can access only those variables declared locally within the monitor and its formal parameters. Similarly, the local variables of a monitor can be accessed by only the local procedures. 4.7.1 Dining-Philosophers Solution Using Monitors This solution imposes the restriction that a philosopher may pick up her chopsticks only if both of them are available. To code this solution, we need to distinguish among three states in which we may find a philosopher. For this purpose, we introduce the following data structure: enum {thinking, hungry, eating}state [5]; Philosopher i can set the variable state [i] = eating only if her two neighbors are not eating: (state [(i+4) % 5] != eating) and (state [(i+1) % 5] != eating). We also need to declare condition self [5]; where philosopher i can delay herself when she is hungry but is unable to obtain the chopsticks she needs. The distribution of the chopsticks is controlled by the monitor dp, whose definition is shown below.(next page) Each philosopher, before starting to eat, must invoke the operation pickup (). This may result in the suspension of the philosopher process. After the successful completion of the operation, the philosopher may eat. Following this, the philosopher invokes the putdown() operation. Thus, philosopher i must invoke the operations pickup() and putdown() in the following sequence: dp.pickup(i); ... eat ...
www.bookspar.com
4.7.3 Implementing a Monitor Using Semaphores We now consider a possible implementation of the monitor mechanism using semaphores. For each monitor, a semaphore mut ex (initialized to 1) is provided. A process must execute wait(mutex) before entering the monitor and must execute signal (mutex) after leaving the monitor. Since a signaling process must wait until the resumed process either leaves or waits, an additional semaphore, next, is introduced, initialized to 0, on which the signaling processes may suspend themselves. An integer variable next_count is also provided to count the number of processes suspended on next. Thus, each external procedure F is replaced by wait(mutex) ; ... body of F ... if (next_count > 0) signal(next); else signal(mutex); Mutual exclusion within a monitor is ensured. We can now describe how condition variables are implemented. For each condition x, we introduce a semaphore x_sem and an integer variable x_count, both initialized to 0. The operation x. wait () can now be implemented as x_count++; if (next_count > 0) signal(next);
www.bookspar.com
www.bookspar.com