350 likes | 354 Views
Learn about mutual exclusion, deadlock, and solutions to critical section issue. Explore algorithms and correctness criteria in parallel systems. See the role of Spin model checker in verifying solutions.
E N D
COMP60611Fundamentals of Parallel and Distributed Systems Lecture 12 The Critical Section problem John Gurd, Graham Riley Centre for Novel Computing School of Computer Science University of Manchester
Introduction • Definition of the critical section problem • Correctness issues • mutual exclusion, deadlock and starvation • Critical look at two attempted solutions • The role of the state diagram in evaluating correctness • The role of the Spin model checker • Summary
Critical section problem • Arises when multiple processes need to share resources. • For example, remember the example of interference where two processes were both incrementing the same shared, global variable. • The correct implementation required some form of locking to synchronise the actions of the two processes. • Other examples include: • Access to shared resources such as a printer or monitor screen. • Updates to a shared bank account via multiple cash dispenser/ATMs (and the bank adding interest at the same time!).
The general Critical Section problem • We will attempt to solve the general Critical Section (CS) problem using only (atomic) reads and writes to shared memory. • i.e. not using any advanced synchronisation mechanisms! • This problem provides good insight into the major problems involved in developing (correct) concurrent programs: • Mutual exclusion, deadlock, starvation, fairness. • We will also use the model checker jSpin to explore the algorithms we develop and see how that tool can help with the development of correct solutions.
Motivation • In exploring solutions to the CS problem we will focus on the structure of the underlying state space and the state transitions that occur • Remember the state diagram captures the entire state space and all possible computations (execution paths a program may take). • A specific computation (execution of a program) takes a particular path through the state space. • We will seek to interpret the correctness criteria for the CS problem in terms of ‘good’ and ‘bad’ states and the paths a computation may take through the state space. • A good solution will have a state space with no bad states. • An automated model checker will be seen as a vital tool, since state spaces are generally too large for manual checking.
Definition of Critical Section problem • Each of N processes is executing in an infinite loop a sequence of statements. • The sequence of statements can be divided into two subsequences: • the non-critical section and the critical section • We consider a two process version • but such ‘toy’ problems are invaluable and the lessons learned can be applied to full size, complex problems.
Correctness • Any correct implementation must satisfy: • Mutual exclusion: statements from the critical sections of two or more processes must not be interleaved. • Freedom from deadlock: If some processes are trying to enter their critical sections then one of them must eventually succeed. • Freedom from (individual) starvation: If any process tries to enter its critical section then that process must eventually succeed. • Mutual exclusion and freedom from deadlock are safety properties • Always true throughout a computation. • Freedom from starvation is a liveness or progress property • Something must eventually be true (i.e. happen) in a computation.
Outline of a solution • We must provide a synchronisation mechanism that satisfies the correctness specification. • The synchronisation mechanism consists of additional statements that are placed before and after the critical section (CS). • The statements before the CS are called the preprotocol. • The statements after the CS are called the postprotocol. • A structure for the solution is then…
Outline of algorithm – two processes global variables q local variables loop forever non-critical section preprotocol critical section postprotocol p local variables loop forever non-critical section preprotocol critical section postprotocol
Further conditions… • The protocols may require both local and global variables • but we assume that no variables used in the critical and non-critical sections are used in the protocol. • The critical section must progress. • Once a process starts to execute the statements of its critical section it must eventually finish executing them • (this property would have to be proved separately by the developer) • The non-critical section need not progress. • If the control pointer of a process is at or within the non-critical section (NCS), the process may terminate (for some reason) or even enter an infinite loop and not leave the NCS. • Makes the problem quite general! Non progress in one process should not hinder other processes.
First attempt – Promela model active proctype Q() { do q1: :: printf("NCS Q\n"); q2:turn == 2; /*await */ q3: printf("CS Q\n"); q4:turn = 1; od } byte turn=1; active proctype P() { do p1: :: printf("Non-critical section P\n"); p2:turn == 1; /* await turn set to 1 */ p3: printf("Critical section P\n"); p4:turn = 2; /* set turn to 2 */ od } NB: The green labels are NOT part of Promela!
Correctness and the state diagram • First, we will look informally at the state diagram to see how the correctness requirements (mutual exclusion, freedom from deadlock and freedom from starvation) may be verified. • Later we will use the model checker jSpin to support the checking of the properties of the state diagram. • Observe that: • P is in its CS when its control pointer is at p3 and p4 • Q is in its CS when its control pointer is at q3 and q4 • Remember the control pointer points to the next instruction
Correctness – Mutual exclusion • “Statements from the critical sections of two or more processes must not be interleaved.” • We can see that there is no state in which the control pointers of both P and Q point to statements in their critical sections. • There is no state with p3 or p4 and q3 or q4 • Mutual exclusion holds! • We simply search the state diagram • A tool could obviously do this for us.
Aside: ‘simultaneous’ statements: in the state diagram - interleaving and multiple paths! p1,q1,1 p1,q2,1 p2,q1,1 p2,q2,1
Freedom from deadlock • “If some processes are trying to enter their critical sections then one of them must eventually succeed.” • P is trying to enter its CS when the control pointer is at p2 (awaiting turn to have the value 1. p2: turn==1) • Q is trying to enter its CS when the control pointer is at q2 (q2: turn==2) • This is slightly more tricky, but since the behaviour of processes P and Q is symmetrical, we only have to check what happens for one of the processes, say P. • Freedom from deadlock means that from any state where a process wishes to enter its CS (by awaiting its turn), there is always apath (sequence of transitions) leading to it entering its CS. • i.e. the control pointer can always move to point to p3.
Freedom from deadlock? p2,q2,1 p2,q1,1 p2,q1,2 p2,q2,2 p2,q3,2 p2,q4,2 There is always a path for P to execute p2 (turn==1)
Observation • Note also that once P has entered its CS, and Q is trying to enter its CS, eventually, Q can enter too. • Because of the assumption of progress in a CS (remember that assumption?), P must eventually leave its CS leading to a state where, if Q tries to enter, it will succeed. • and vice-versa. • Freedom from deadlock in the first attempt holds! • We will see later that, typically, a deadlocked state has no transitions leading from it, i.e. no statement is able to be executed. • Sometimes a cycle of transitions may exist from a state for each process, from which no useful progress in the parallel program can be made. The program is still deadlocked but this situation is sometimes termed ‘livelock’. Every one is ‘busy doing nothing’.
Freedom from individual starvation • “If any process tries to enter its critical section then that process must eventually succeed.” • If a process is wishing to enter its CS (awaiting its turn) and another process refuses to set the turn, the first process is said to be starved. • Possible starvation reveals itself as cycles in the state diagram. • Because the definition of the critical section problem allows for a process to not make progress from its Non-critical section, starvation is, in general, possible in the first attempt… • NOTE, however, that the printf statement in this version of the first attempt will always execute, so there is no starvation in this model. • We will introduce a non critical section that does not guarantee progress in a future lecture and in the lab exercises – and see what jSpin has to say about it.
Freedom from starvation? p1,q2,1 p2,q1,2 Non-progress from p1 in NCS by P will starve Q! Q will stay in its loop awaiting turn==2 (similarly for Q from q1)
Summary • Think of turn as a permission resource for entering the critical section. • Its value indicates which process holds the resource. • Some process always holds the resource (turn always 1 or 2) • So some process can always enter the CS • No deadlock! • But if the process holding the resource does not leave its Non-CS – as allowed by the assumptions of the problem – the other process will be starved. • Next we will attempt to ensure that a process staying in its non-CS cannot prevent another process from entering its CS. • Give each process its own variable…
2nd attempt - observations • The idea is that wantp (wantq) is true from the step where process P (Q) wants to enter its CS until it leaves. • Await statements ensure that one process does not enter its CS while the other process has its flag set. • The problem of failure in the NCS does not occur since a process’ flag will be false in the NCS, so the other process will always succeed in entering its CS.
Second attempt - Promela active proctype Q() { do q1: :: printf("NCS Q\n"); q2:!wantp; /*await */ q3:wantq = true; q3: printf("CS Q\n"); q4:wantq = false; od } bool wantp = false; bool wantq = false; active proctype P() { do p1: :: printf("Non-critical section P\n"); p2:!wantq; /* await turn */ p3:wantp = true; p4: printf("Critical section P\n"); p5:wantp=false; od }
Mutual exclsusion? • But, what about mutual exclusion etc. • examine the state diagram as before • We don’t need to build all the state diagram. If we find a ‘bad’ state (where both processes are in their CS), that is sufficient. • If there is a computation (path) that includes the bad state, the program is incorrect. • We can ignore the printf statements - since they will always execute – and focus on the logic of the synchronisation variables… • This is known as the ‘reduced’ algorithm. • Note: smaller models have advantages - both for manual reasoning and for performnace in jSpin.
Fragment of the state diagram – 2nd attempt Both processes are in their CS at the same time so mutual exclusion does not hold!
Observations • Note that we do not necessarily have to have the entire state diagram available at once! • We can build it incrementally • This is useful for an automated model checker • Saves memory (state diagrams can be very big). • Also, as soon as we find a bad state, we can stop. • If there are no bad states though, we will have checked every state in the state diagram. • Another reason for automation.
Next attempt at the CS problem? • We will explore the CS problem, including a correct solution to it, in the lab. • We will explore the use of jSpin in helping to establish the correctness properties. • Instead of constructing the state diagram and examinig it manually, we use jSpin to explore it for us. • We just have to ask the right questions…
Asking questions of jSpin – auxiliary variables and assertions • To check properties like mutual exclusion we have (informally) talked about the location of the control pointers of the processes • For mutual exclusion to hold, no more than one control pointer should be in the critical section at a time. • The values of control pointers and values of the program variables make up the state of the program. • Thus, proving properties of programs becomes asking Spin to check for certain conditions on the state of the program in any computation (path through the state space) the program may execute. • One way to specify properties is to use auxiliary variables (sometimes called ‘ghost variables’).
Auxiliary variables • We add variables to the program that have a meaning in terms of the properties we wish to check. • The auxiliary variables are not used elsewhere in the program so they cannot affect the correctness of the algorithm. • For example, to check mutual exclusion we introduce a counting variable, critical, into the program. • We initialise critical to zero. • We increment critical when a process has entered its critical section. • We decrement critical just before a process leaves its critical section. • If mutual exclusion holds, what is the maximum value the variable critical should take? • We can get Spin to test this using an assertion!
Example in attempt 2 bool wantp = false; bool wantq = false; byte critical = 0; /* aux variable */ active proctype P() { do :: printf("Non-critical section P\n"); !wantq; /* await turn */ wantp = true; critical++; printf("Critical section P\n"); assert(critical<=1); critical--; wantp=false; od } active proctype Q() { do :: printf("NCS Q\n"); !wantp;/*await */ wantq = true; critical++; printf("CS Q\n"); assert(critical<=1); critical--; wantq = false; od }
Use of jSpin • Use jSpin to investigate check the assertion. • Use Verify in Safety mode (with weak fairness selected). • The assertion does not hold! • Look at the trail produced to see why. • We will investigate the use of assertions and jSpin in lab exercise 3.
Conclusion • Focussed on the general critical section problem. • And the correctness properties of mutual exclusion, freedom from deadlock and freedom from starvation. • We have found that the state transition diagram has the answers to whether correctness properties hold. • The state diagram contains all reachable states and all the paths through the state space (i.e. the possible computations). • Properties are evaluated in terms of the state space. • State spaces are generally too large to examine by hand/eye, so tools are essential. • Spin is one such tool and we have seen how to check properties using auxiliary variables and assertions with Spin.