in data inconsistency • Maintaining data consistency requires mechanisms to ensure the orderly execution of cooperating processes • cooperating processes: processes that access the shared data • Example: in producer-consumer program – an integer count • keeps track of the number of full buffers • Initially set to 0 • Shared by the producer and the consumer – incremented by the producer after it produces a new full buffer – decremented by the consumer after it consumes a full buffer
code, in which the process may update shared data • When a process is in the critical section, others cannot enter that section – no two processes in the same critical section at the same time • Critical section problem – Design a protocol that processes can use to coordinate • Entry section: code to try/request to enter the critical section • Exit section: code that follows the critical section
the following requirements 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 – guarantee a given process will finally be selected • Assume that each process executes at a nonzero speed
critical section problem requires a simple tool – a lock (ensure mutual exclusion) do { Acquire lock Critical section Release lock Remainder section } while (TRUE) • Lock can be implemented in different ways….
locks • Ref: for uniprocessor – could disable interrupts – Currently running code would execute without preemption – The approach used by non-preemptive kernels to protect shared data in the kernels – Generally too inefficient on multiprocessor systems • Operating systems using this not broadly scalable • Need to ask other processors to disable interrupts – Clocks may stop in the critical section
instructions • Atomic = non-interruptable – Example 1 • test-and-set instruction: test memory word and set value – Example 2 • swap instruction: swap contents of two memory words
• Typical semaphore implementations do NOT require busy waiting – described later • Semaphore S – integer variable • Two standard operations modify S: wait() and signal() – Originally called P() and V() • Can only be accessed via two indivisible (atomic) operations – wait (S) { while S <= 0 // atomic for each iteration ; // no-op // iteration: if S>0, S--; else, blocking until S>0 S--; } – signal (S) { S++; // atomic }
• Note that applications may spend lots of time in critical sections. In this case, busy waiting is not a good approach. • Solution – Sleep/block instead of busy waiting
the semaphore value, each semaphore has an associated waiting queue • Require blocking/waking-up a process – block • switch process state to “waiting” • remove the process from the ready queue – wakeup • switch process state to “ready” • place the process in the ready queue • Both operations may lead to the invocation of the scheduler
wait: wait (S){ value--; if (value < 0) { // the value can be negative ➔ # of processes waiting add this process to the waiting queue block(); /* suspend the process */ } } • Implementation of signal: Signal (S){ value++; if (value <= 0) { remove a process P from the waiting queue wakeup(P); } }
– A list of PCBs – FIFO ➔ ensure bounded waiting • Must guarantee that no two processes can execute wait() and signal() on the same semaphore at the same time – The implementation in the previous slide should be atomic • Thus, implementation becomes the critical section problem where the wait and signal code are placed in the critical section. – For uniprocessor ➔ disable interrupt – For MP ➔ typically use spinlocks ( busy waiting ) • Acceptable for busy waiting in critical sections of the wait() and signal() operations since they are short…
processes are waiting infinitely for an event that can be caused by only one of the waiting processes – Let S and Q be two semaphores initialized to 1 P 0 P 1 wait (S); wait (Q); wait (Q); wait (S); . . . . . . signal (S); signal (Q); signal (Q); signal (S); • Starvation – infinite blocking. A process may never be removed from the semaphore queue in which it is suspended.
an item • Players – Producers • produce full buffers, wait for empty buffers – Consumers • produce empty buffers, wait for full buffers • Use 3 semaphores – mutex initialized as 1 – full initialized as 0 – empty initialized as N
consumer process do { wait (full); wait (mutex); // remove an item from buffer signal (mutex); signal (empty); // consume the removed item } while (true);
a number of concurrent processes – Readers – only read the data set; they do not perform any updates – Writers – can both read and write. • Problem – How to allow multiple readers to read at the same time? Of course, only one single writer can access the shared data at the same time. • Shared Data – Data set – Integer readcount initialized to 0. // number of readers – Semaphore mutex initialized to 1. // mutex on readcount – Semaphore wrt initialized to 1. // contention with a writer
process do { wait (mutex) ; // mutex: for updating and maintaining readcount readcount ++ ; if (readercount == 1) wait (wrt) ; // the following readers do not wait(wrt) signal (mutex) // reading is performed wait (mutex) ; readcount -- ; if (redacount == 0) signal (wrt) ; signal (mutex) ; } while (true) •If a writer is in the critical section and n readers are waiting, then one reader is blocked on wrt and the other n-1 readers are blocked on mutex •On signal (wrt), we can wakeup a set of readers or a single writer
Using the reader-writer locks – Specify the lock mode: read or write • Useful in the following situations – When it is easy to identify r/w access mode – More readers than writers
– P = {P 1 , P 2 , …, P n }, the set consisting of all the processes in the system – R = {R 1 , R 2 , …, R m }, the set consisting of all resource types in the system • request edge – directed edge P i → R j • assignment edge – directed edge R j → P i A set of vertices V and a set of edges E
no deadlock • If graph contains a cycle ⇒ – if only one instance per resource type, then deadlock – if several instances per resource type, possibility of deadlock
will never enter a deadlock state – Deadlock prevention or avoidance • Allow the system to enter a deadlock state and then recover • Ignore the problem and pretend that deadlocks never occur in the system – used by most operating systems (UNIX, Windows..) – applications have to deal with deadlocks themselves
at a time can use a resource • Hold and wait – a process holding at least one resource is waiting to acquire additional resources held by other processes • No preemption – a resource can be released only voluntarily by the process holding it • Circular wait – there exists a set of waiting processes {P 1 , P 2 , …, P n } such that P 1 is waiting for a resource held by P 2 , P 2 is waiting for a resource held by P 3 , …, P n–1 is waiting for a resource held by P n , and P n is waiting for a resource held by P 1 Deadlock can occur if four conditions hold simultaneously.
made – Ensure at least one of the four conditions cannot hold • Mutual Exclusion – not required for sharable resources; must hold for non-sharable resources • Hold and Wait – must guarantee that whenever a process requests a resource, it does not hold any other resources – Require process to request and be allocated all its resources before it begins execution, or allow process to request resources only when the process has none – Starvation possible • A process that needs several popular resources may wait infinitely
a process holding some resources requests another resource that cannot be immediately allocated to it, then all resources currently being held are released (i.e., preempt the resource holding) – Preempted resources are added to the list of resources for which the process is waiting – Process will be restarted only when it can regain its old resources, as well as the new one that it is requesting • Circular Wait – – impose a total ordering of all resource types, and require that each process requests resources in an increasing order of enumeration • Lock-order verifier. example: witness (BSD)
graph – Nodes are processes – P i → P j if P i is waiting for P j • Periodically invoke an algorithm that searches for a cycle in the graph • An algorithm to detect a cycle in a graph requires an order of n2 operations, where n is the number of vertices in the graph
vector of length m indicates the number of available resources of each type • Allocation: An n x m matrix defines the number of resources of each type currently allocated to each process. If Allocation [i, j] = k, then process P i now has k instances of resource type R j • Request: An n x m matrix indicates the current request of each process. If Request [i, j] = k, then process P i is requesting k more instances of resource type R j n: number of processes m: number of resource types
of length m and n, respectively. Initial condition: (a) Work = Available (b) For i = 1,2, …, n, Finish[i] = false 2. Find an index i such that both: (a) Finish[i] == false (b) Request i ≤ Work If no such i exists, go to step 4.
i Finish[i] = true go to step 2. 4. If Finish[i] == false, for some i, 1 ≤ i ≤ n, then the system is in deadlock state. Moreover, if Finish[i] == false, then P i is in a deadlock state. Optimistically assumes that Pi will release its resources after the request. If the assumption is not correct, deadlock may occur later. - detected by the later invocation of the detection algorithm
through P 4 • 3 resource types: A (7 instances), B (2 instances), C (6 instances). • Snapshot at time T 0 : Allocation Request Available A B C A B C A B C P 0 0 1 0 0 0 0 0 0 0 P 1 2 0 0 2 0 2 P 2 3 0 3 0 0 0 P 3 2 1 1 1 0 0 P 4 0 0 2 0 0 2 • Sequence <P 0 , P 2 , P 3 , P 1 , P 4 > will result in Finish[i] = true for all i.
of type C. Request A B C P 0 0 0 0 P 1 2 0 2 P 2 0 0 1 P 3 1 0 0 P 4 0 0 2 • Is the system in deadlock state? – Can reclaim resources held by process P 0 , but insufficient resources to fulfill other processes – Deadlock exists, consisting of processes P 1 , P 2 , P 3 , and P 4
It depends on – How often a deadlock is likely to occur? – How many processes will be affected? • Possible ways – Invoked at each request that needs to wait – Invoked periodically – Invoked at specific situations • E.g., when the system throughput suddenly drops
processes • Abort one process at a time until the deadlock cycle is eliminated – in which order should we choose to abort? • Priority of the process • How long process has computed, and how much longer to completion • Resources the process holds • Resources a process needs to complete
from some processes and give the resources to other processes • Selecting a victim – minimize cost • Rollback – return to some safe state, restart process from that state • Starvation – a process may always be selected as the victim – May need to include number of rollback in the cost factor