Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

83
Chapter 5 1 Concurrency: Mutual Concurrency: Mutual Exclusion and Exclusion and Synchronization Synchronization Chapter 5 Chapter 5
  • date post

    22-Dec-2015
  • Category

    Documents

  • view

    244
  • download

    7

Transcript of Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Page 1: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 51

Concurrency: Mutual Exclusion and Concurrency: Mutual Exclusion and SynchronizationSynchronization

Chapter 5Chapter 5

Page 2: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 52

Problems with concurrent executionProblems with concurrent execution

Concurrent processes (or threads) often need to share data (maintained either in shared memory or files) and resources

If there is no controlled access to shared data, execution of the processes on these data can interleave.

The results will then depend on the order in which data were modified (nondeterminism).

A program may give different and sometimes undesirable results each time it is executed

Page 3: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 53

An exampleAn example

Process P1 and P2 are running this same procedure and have access to the same variable “a” shared variable

Processes can be interrupted anywhere

If P1 is first interrupted after user input and P2 executes entirely

Then the character echoed by P1 will be the one read by P2 !!

static char a;

void echo(){ cin >> a; cout << a;}

Page 4: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 54

Global view: possible interleaved execution Global view: possible interleaved execution

Process P1

static char a;

void echo(){ cin >> a;

cout << a;}

Process P2

static char a;

void echo(){ cin >> a; cout << a;}

CS

CS

CS: Critical Section: part of a program whose execution cannot interleave with the execution of other CSs

Page 5: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 55

Race conditionsRace conditions

Situations such as the preceding one, where processes are racing against each other for access to ressources (variables, etc.) and the result depends on the order of access, are called race conditions

In this example, there is race on the variable a

Non-determinism: results don`t depend exclusively on input data, they depend also on timing conditions

Page 6: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 56

Other examplesOther examples

A counter that is updated by several processes, if the update requires several instructions (p.ex. in machine language)

Threads that work simultaneously on an array, one to update it, the other to extract stats

Processes that work simultaneouosly on a database, for example in order to reserve airplane seats Two travellers could get the same seat...

In this chapter, we will talk normally about concurrent processes. The same considerations apply to concurrent threads.

Page 7: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 57

The critical section problemThe critical section problem

When a process executes code that manipulates shared data (or resources), we say that the process is in a critical section (CS) (for that shared data or resource)

CSs can be thought of as sequences of instructions that are ‘tightly bound’ so no other CSs on the same data or resource can interleave.

The execution of CSs must be mutually exclusive: at any time, only one process should be allowed to execute in a CS for a given shared data or resource (even with multiple CPUs) the results of the manipulation of the shared data or resource

will no longer depend on unpredictable interleaving The CS problem is the problem of providing special

sequences of instructions to obtain such mutual exclusion These are sometimes called synchronization mechanisms

Page 8: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 58

CS: Entry and exit sectionsCS: Entry and exit sections A process wanting to enter a critical section must ask for

permission The section of code implementing this request is called the

entry section The critical section (CS) will be followed by an exit section,

which opens the possibility of other processes entering their CS.

The remaining code is the remainder section

repeat entry section critical section exit section remainder sectionforever

Page 9: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 59

Framework for analysis of solutionsFramework for analysis of solutions

Each process executes at nonzero speed but there are no assumption on the relative speed of processes, nor on their interleaving

Memory hardware prevents simultaneous access to the same memory location, even with several CPUs this establishes a sort of elementary critical

section, on which all other synch mechanisms are based

Page 10: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 510

Requirements for a valid solution to the critical Requirements for a valid solution to the critical section problemsection problem Mutual Exclusion

At any time, at most one process can be in its critical section (CS)

Progress Only processes that are not executing in their

Remainder Section are taken in consideration in the decision of who will enter next in the CS.

This decision cannot be postponed indefinitely

Page 11: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 511

Requirements for a valid solution to the critical Requirements for a valid solution to the critical section problem (cont.)section problem (cont.) Bounded Waiting

After a process P has made a request to enter its CS, there is a limit on the number of times that the other processes are allowed to enter their CS, before P gets it: no starvation

Of course also no deadlock

It is difficult to find solutions that satisfy all criteria and so most solutions we will see are defective on some aspects

Page 12: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 512

3 Types of solutions3 Types of solutions

No special instructions (book:software appr.)

algorithms that don’t use instructions designed to solve this particular problem

Hardware solutions rely on special machine instructions (e.g. Lock bit)

Operating System and Programming Language solutions (e.g. Java) provide specific system calls to the

programmer

Page 13: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 513

Software solutionsSoftware solutions

We consider first the case of 2 processes Algorithm 1 and 2 have problems Algorithm 3 is correct (Peterson’s algorithm)

Notation We start with 2 processes: P0 and P1 When presenting process Pi, Pj always

denotes the other process (i != j)

Page 14: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 514

Process P0:repeat flag[0]:=true; while(flag[1])do{}; CS flag[0]:=false; RSforever

Process P1:repeatflag[1]:=true; while(flag[0])do{}; CS flag[1]:=false; RSforever

Algorithm 2 global view

P0: flag[0]:=trueP1: flag[1]:=truedeadlock!

Algorithm 1 or the excessive courtesyAlgorithm 1 or the excessive courtesy

Page 15: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 515

Algorithm 1 or the excessive courtesyAlgorithm 1 or the excessive courtesy

Keep 1 Bool variable for each process: flag[0] and flag[1]

Pi signals that it is ready to enter its CS by: flag[i]:=true but it gives first a chance to the

other Mutual Exclusion, progress OK but not the deadlock requirement If we have the sequence:

P0: flag[0]:=true P1: flag[1]:=true

Both processes will wait forever to enter their CS: deadlock

Could work in other cases!

Process Pi:repeatflag[i]:=true; while(flag[j])do{}; CSflag[i]:=false; RSforever

Page 16: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 516

Process P0:repeat while(turn!=0)do{}; CS turn:=1; RSforever

Process P1:repeat while(turn!=1)do{}; CS turn:=0; RSforever

Algorithm 1 global view

Note: turn is a shared variable between the two processes

Algorithm 2—Strict OrderAlgorithm 2—Strict Order

Page 17: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 517

Algorithm 2—Strict OrderAlgorithm 2—Strict Order The shared variable turn is

initialized (to 0 or 1) before executing any Pi

Pi’s critical section is executed iff turn = i

Pi is busy waiting if Pj is in CS: mutual exclusion is satisfied

Progress requirement is not satisfied since it requires strict alternation of CSs.

If a process requires its CS more often then the other, it can’t get it.

Process Pi: //i,j= 0 or 1repeat while(turn!=i)do{}; CS turn:=j; RSforever

do nothing

Page 18: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 518

Process P0:repeat flag[0]:=true; // 0 wants in turn:= 1; // 0 gives a chance to 1 while (flag[1]&turn=1)do{}; CS flag[0]:=false; // 0 no longer wants in RSforever

Process P1:repeat flag[1]:=true; // 1 wants in turn:=0; // 1 gives a chance to 0 while (flag[0]&turn=0)do{}; CS flag[1]:=false; // 1 no longer wants in RSforever

Peterson’s algorithm global view

Algorithm 3 (Peterson’s algorithm)Algorithm 3 (Peterson’s algorithm) (forget about Dekker)(forget about Dekker)

Page 19: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 519

Wait or enter?Wait or enter?

A process i waits if: the other process wants in and its turn has

come flag[j]and turn=j

A process i enters if: It wants to enter or its turn has come

flag[i] or turn=i in practice, if process i gets to the test, flag[i] is

necessarily true so it`s turn that counts

Page 20: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 520

Algorithm 3 (Peterson’s algorithm)Algorithm 3 (Peterson’s algorithm) (forget about Dekker)(forget about Dekker)

Initialization: flag[0]:=flag[1]:=false turn:= 0 or 1

Interest to enter CS specified by flag[i]:=true

flag[i]:= false upon exit

If both processes attempt to enter their CS simultaneously, only one turn value will last

Process Pi:repeat flag[i]:=true; // want in turn:=j; // but give a chance... while (flag[j]&turn=j)do{}; CS flag[i]:=false; // no longer want in RSforever

Page 21: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 521

Algorithm 3: proof of correctnessAlgorithm 3: proof of correctness

Mutual exclusion holds since: P0 and P1 are both in CS only if flag[0] = flag[1] =

true and only if turn = i for each Pi (impossible)

We now prove that the progress and bounded waiting requirements are satisfied: Pi cannot enter CS only if stuck in while{} with

condition flag[ j] = true and turn = j. If Pj is not ready to enter CS then flag[ j] = false

and Pi can then enter its CS

Page 22: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 522

Algorithm 3: proof of correctness (cont.)Algorithm 3: proof of correctness (cont.)

If Pj has set flag[ j]=true and is in its while{}, then either turn=i or turn=j

If turn=i, then Pi enters CS. If turn=j then Pj enters CS but will then reset flag[ j]=false on exit: allowing Pi to enter CS

but if Pj has time to reset flag[ j]=true, it must also set turn=i

since Pi does not change value of turn while stuck in while{}, Pi will enter CS after at most one CS entry by Pj (bounded waiting)

Page 23: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 523

What about process failures?What about process failures?

If all 3 criteria (ME, progress, bounded waiting) are satisfied, then a valid solution will provide robustness against failure of a process in its remainder section (RS) since failure in RS is just like having an infinitely long

RS. However, the solution given does not provide

robustness against a process failing in its critical section (CS). A process Pi that fails in its CS without releasing the CS

causes a system failure it would be necessary for a failing process to inform the

others, perhaps difficult!

Page 24: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 524

Extensions to >2 processesExtensions to >2 processes

Peterson algorithm can be generalized to >2 processes

But in this case there is a more elegant solution...

Page 25: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 525

n-process solution: bakery algorithm n-process solution: bakery algorithm (not in book)(not in book)

Before entering their CS, each Pi receives a number. Holder of smallest number enter CS (like in bakeries, ice-cream stores...)

When Pi and Pj receive same number: if i<j then Pi is served first, else Pj is served first

Pi resets its number to 0 in the exit section Notation:

(a,b) < (c,d) if a < c or if a = c and b < d max(a0,...ak) is a number b such that

b >= ai for i=0,..k

Page 26: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 526

The bakery algorithm (cont.)The bakery algorithm (cont.)

Shared data: choosing: array[0..n-1] of boolean;

initialized to false number: array[0..n-1] of integer;

initialized to 0 Correctness relies on the following fact:

If Pi is in CS and Pk has already chosen its number[k]!= 0, then (number[i],i) < (number[k],k)

but the proof is somewhat tricky...

Page 27: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 527

The bakery algorithm (cont.)The bakery algorithm (cont.)

Process Pi:repeat choosing[i]:=true; number[i]:=max(number[0]..number[n-1])+1; choosing[i]:=false; for j:=0 to n-1 do { while (choosing[j]) {}; while (number[j]!=0 and (number[j],j)<(number[i],i)){}; } CS number[i]:=0; RSforever

Page 28: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 528

Drawbacks of software solutionsDrawbacks of software solutions

Complicated logic! Processes that are requesting to enter in

their critical section are busy waiting (consuming processor time needlessly)

If CSs are long, it would be more efficient to block processes that are waiting (just as if they had requested I/O).

We will now look at solutions that require hardware instructions the first ones will not satisfy criteria above

^Low Level

Page 29: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 529

A simple hardware solution: interrupt disablingA simple hardware solution: interrupt disabling

Observe that in a uniprocessor system the only way a program can interleave with another is if it gets interrupted

So simply disable interruptions Mutual exclusion is preserved

but efficiency of execution is degraded: while in CS, we cannot interleave execution with other processes that are in RS

On a multiprocessor: mutual exclusion is not achieved Generally not an acceptable

solution

Process Pi:repeat disable interrupts critical section enable interrupts remainder sectionforever

Page 30: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 530

Hardware solutions: special machine Hardware solutions: special machine instructionsinstructions

Normally, access to a memory location excludes other access to that same location

Extension: machine instructions that perform several actions atomically (indivisible) on the same memory location (ex: reading and testing)

The execution of such instruction sequences is mutually exclusive (even with multiple CPUs)

They can be used to provide mutual exclusion but need more complex algorithms for satisfying the other requirements of the CS problem

Page 31: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 531

The test-and-set instructionThe test-and-set instruction

A C description of test-and-set:

An algorithm that uses testset for Mutual Exclusion:

Shared variable b is initialized to 0

Only the first Pi who sets b enter CS

bool testset(int& i){ if (i==0) { i=1; return true; } else { return false; }}

Process Pi:repeat repeat{} until testset(b); CS b=0; RSforeverNon Interruptible!

Page 32: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 532

The test-and-set instruction (cont.)The test-and-set instruction (cont.)

Mutual exclusion is assured: if Pi enter CS, the other Pj are busy waiting but busy waiting is not a good way!

Needs other algorithms to satisfy the additional criteria When Pi exit CS, the selection of the Pj who will enter

CS is arbitrary: no bounded waiting. Hence starvation is possible

Still a bit too complicated to use in everyday code

Page 33: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 533

ExchangeExchange instruction: similar idea instruction: similar idea

Processors (ex: Pentium) often provide an atomic xchg(a,b) instruction that swaps the content of a and b.

But xchg(a,b) suffers from the same drawbacks as test-and-set

Page 34: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 534

Using xchg for mutual exclusionUsing xchg for mutual exclusion

Shared variable lock is initialized to 0

Each Pi has a local variable key

The only Pi that can enter CS is the one who finds lock=0

This Pi excludes all the other Pj by setting lock to 1

Process Pi:repeat key:=1 repeat exchg(key,lock) until key=0; CS lock:=0; RSforever

Page 35: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 535

Solutions based on systems callsSolutions based on systems calls

Appropriate machine language instructions are at the basis of all practical solutions but they are too elementary

We need instructions allowing to better structure code.

We also need better facilities for preventing common errors, such as deadlocks, starvation, etc.

So there is need of instructions at a higher level Such instructions are implemented as system

calls

Page 36: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 536

SemaphoresSemaphores

A semaphore S is an integer variable that, apart from initialization, can only be accessed through 2 atomic and mutually exclusive operations: wait(S) signal(S)

It is shared by all processes who are interested in the same resource, shared variable, etc.

Semaphores will be presented in two steps: busy wait semaphores semaphores using waiting queues

A distinction is made between counter semaphores and binary semaphores we`ll see the applications

Page 37: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 537

Busy Waiting Semaphores Busy Waiting Semaphores (spinlocks)(spinlocks)

The simplest semaphores.

Useful when critical sections last for a short time, or we have lots of CPUs.

S initialized to positive value (to allow someone in at the beginning).

signal(S): S++;

wait(S): while S<=0 do{}; S--;

waits if # of proc who can enter is 0 or negative

increases by 1 the number of processes that can enter

Page 38: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 538

Atomicity aspectsAtomicity aspects

The testing and decrementing sequence in wait are atomic, but not the loop.

Signal is atomic. No two processes can be

allowed to execute atomic sections simultaneously. This can be implemented

by some of the mechanisms discussed earlier

S <= 0

atomic S - -

F

T

Page 39: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 539

Atomicity and InterruptibilityAtomicity and Interruptibility

S <= 0

atomic S - -

F

TS++interruptible

other process

The loop is not atomic to allow another process to interrupt the wait

Page 40: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 540

Using semaphores for solving critical section Using semaphores for solving critical section problems problems

For n processes Initialize S to 1 Then only 1 process is

allowed into CS (mutual exclusion)

To allow k processes into CS, we initialize S to k

So semaphores can allow several processes in the CS!

Process Pi:repeat wait(S); CS signal(S); RSforever

Page 41: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 541

Process P0:repeat

wait(S); CS

signal(S); RSforever

Process P1:repeat wait(S); CS signal(S); RSforever

Semaphores: the global view

Initialize S to 1

Page 42: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 542

Using semaphores to synchronize processesUsing semaphores to synchronize processes

We have 2 processes: P1 and P2

Statement S1 in P1 needs to be performed before statement S2 in P2

Then define a semaphore “synch”

Initialize synch to 0

Proper synchronization is achieved by having in P1: S1; signal(synch);

And having in P2: wait(synch); S2;

Page 43: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 543

Semaphores: observationsSemaphores: observations

When S>=0: the number of processes that can execute wait(S)

without being blocked = S S processes can enter CS if S>1 is possible, then a second semaphore is necessary

to implement mutual exclusion • see producer/consumer example

When S >1, the process that enters in the CS is the one that tests S first (random selection). this won’t be true in the following solution

When S<0: the number of processes waiting on S is |S|

wait(S): while S<=0 do{}; S--;

Page 44: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 544

Avoiding Busy Wait in SemaphoresAvoiding Busy Wait in Semaphores

To avoid busy waiting: when a process has to wait for a semaphore to become greater than 0, it will be put in a blocked queue of processes waiting for this to happen.

Queues can be FIFO, or priority, etc.: OS has control on the order processes enter CS.

wait and signal become system calls to the OS (just like I/O calls)

There is a queue for every semaphore just as there is a queue for each I/O unit

A process that waits on a semaphore is in waiting state

Page 45: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 545

Semaphores without busy waitingSemaphores without busy waiting

A semaphore can be seen as a record (structure):

type semaphore = record count: integer; queue: list of process end;var S: semaphore; When a process must wait for a semaphore S, it is

blocked and put on the semaphore’s queue The signal operation removes (by a fair scheduling

policy like FIFO) one process from the queue and puts it in the list of ready processes

Page 46: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 546

Semaphore’s operations (atomic)Semaphore’s operations (atomic)

wait(S): S.count--; if (S.count<0) { block this process place this process in S.queue }

signal(S): S.count++; if (S.count<=0) { remove a process P from S.queue place this process P on ready list }

The value to which S.count is initialized depends on the application

S was negative: queue nonempty

atomic

atomic

Page 47: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 547

Figure showing the relationship between

queue content and value of S

Page 48: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 548

Semaphores: ImplementationSemaphores: Implementation

wait and signal themselves contain critical sections! How to implement them?

Note that they are very short critical sections. Solutions:

uniprocessor: disable interrupts during these operations (ie: for a very short period). This does not work on a multiprocessor machine.

multiprocessor: use some busy waiting scheme, hardware or software. Busy waiting shouldn’t last long.

Page 49: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 549

The producer/consumer problemThe producer/consumer problem

A producer process produces information that is consumed by a consumer process Ex1: a print program produces characters that

are consumed by a printer Ex2: an assembler produces object modules

that are consumed by a loader We need a buffer to hold items that are

produced and eventually consumed A common paradigm for cooperating

processes (see Unix Pipes)

Page 50: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 550

P/C: unbounded bufferP/C: unbounded buffer

We assume first an unbounded buffer consisting of a linear array of elements

in points to the next item to be produced out points to the next item to be consumed

Page 51: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 551

P/C: unbounded bufferP/C: unbounded buffer

We need a semaphore S to perform mutual exclusion on the buffer: only 1 process at a time can access the buffer

We need another semaphore N to synchronize producer and consumer on the number N (= in - out) of items in the buffer an item can be consumed only after it has been

created

Page 52: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 552

P/C: unbounded bufferP/C: unbounded buffer

The producer is free to add an item into the buffer at any time: it performs wait(S) before appending and signal(S) afterwards to prevent consumer access

It also performs signal(N) after each append to increment N

The consumer must first do wait(N) to see if there is an item to consume and use wait(S)/signal(S) to access the buffer

Page 53: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 553

Solution of P/C: unbounded bufferSolution of P/C: unbounded buffer

Producer:repeat produce v; wait(S); append(v); signal(S); signal(N);forever

Consumer:repeat wait(N); wait(S); w:=take(); signal(S); consume(w);forever

Initialization: S.count:=1; //mutual exclusion N.count:=0; //number of items in:=out:=0; //indexes to buffers

critical sections

append(v):b[in]:=v;in++;

take():w:=b[out];out++;return w;

Page 54: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 554

P/C: unbounded bufferP/C: unbounded buffer

Remarks: check that producer can run arbitrarily faster than consumer Putting signal(N) inside the CS of the producer (instead of

outside) has no effect since the consumer must always wait for both semaphores before proceeding

The consumer must perform wait(N) before wait(S), otherwise deadlock occurs if consumer enters CS while the buffer is empty

disaster will occur if one forgets to do a signal after a wait, eg. if a producer has an unending loop inside a critical section.

Using semaphores has pitfalls...

Page 55: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 555

P/C: finite circular buffer of size kP/C: finite circular buffer of size k

can consume only when number N of (consumable) items is at least 1 (now: N!=in-out)

can produce only when number E of empty spaces is at least 1

Page 56: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 556

P/C: finite circular buffer of size kP/C: finite circular buffer of size k

As before: we need a semaphore S to have mutual

exclusion on buffer access we need a semaphore N to synchronize

producer and consumer on the number of consumable items (full spaces)

In addition: we need a semaphore E to synchronize

producer and consumer on the number of empty spaces

Page 57: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 557

Solution of P/C: finite circular buffer of size kSolution of P/C: finite circular buffer of size k

Initialization: S.count:=1; //mutual excl. N.count:=0; //full spaces E.count:=k; //empty spaces

Producer:repeat produce v; wait(E); wait(S); append(v); signal(S); signal(N);forever

Consumer:repeat wait(N); wait(S); w:=take(); signal(S); signal(E); consume(w);forever

critical sections

append(v):b[in]:=v;in++; mod k;

take():w:=b[out];out++; mod k;return w;

Page 58: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 558

The Dining Philosophers ProblemThe Dining Philosophers Problem

5 philosophers who only eat and think

each need to use 2 forks for eating

we have only 5 forks A classical synchron.

problem Illustrates the difficulty

of allocating resources among process without deadlock and starvation

Page 59: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 559

The Dining Philosophers ProblemThe Dining Philosophers Problem

Each philosopher is a process

One semaphore per fork: fork: array[0..4] of

semaphores Initialization:

fork[i].count:=1 for i:=0..4

A first attempt: Deadlock if each

philosopher start by picking his left fork!

Process Pi:repeat think; wait(fork[i]); wait(fork[i+1 mod 5]); eat; signal(fork[i+1 mod 5]); signal(fork[i]); forever

Page 60: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 560

The Dining Philosophers ProblemThe Dining Philosophers Problem

A solution: admit only 4 philosophers at a time to the table

Then 1 philosopher can always eat when the other 3 are holding 1 fork

Hence, we can use another semaphore T that would limit at 4 the numb. of philosophers “sitting at the table”

Initialize: T.count:=4

Process Pi:repeat think; wait(T); wait(fork[i]); wait(fork[i+1 mod 5]); eat; signal(fork[i+1 mod 5]); signal(fork[i]); signal(T); forever

Page 61: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 561

Binary semaphoresBinary semaphores

The semaphores we have studied are called counting (or integer) semaphores

We have also binary semaphores similar to counting semaphores except that

“count” is Boolean valued: 0 or 1 can do anything counting semaphores can do more difficult to use than counting semaphores:

must use additional counting variables protected by binary semaphores.

Page 62: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 562

Binary semaphoresBinary semaphores

waitB(S): if (S.value = 1) { S.value := 0; } else { block this process place this process in S.queue }

signalB(S): if (S.queue is empty) { S.value := 1; } else { remove a process P from S.queue place this process P on ready list }

Page 63: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 563

Advantages of semaphores Advantages of semaphores (w.r.t. previous solutions)(w.r.t. previous solutions)

Only one shared variable per critical section Two simple operations: wait, signal Avoid busy wait, but not completely Can be used in the case of many processes If desired, several processes at a time can be

allowed in (see prod/cons) wait queues managed by the OS: starvation

avoided if OS is `fair` (p.ex. queues FIFO).

Page 64: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 564

Problems with semaphoresProblems with semaphores

But if wait(S) and signal(S) are scattered among several processes but must correspond difficult in complex programs

Usage must be correct in all processes, otherwise global problems can occur

One faulty (or malicious) process can fail the entire collection of processes, cause deadlock, starvation

Consider the case of a process that has waits and signals in loops with tests...

Page 65: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 565

MonitorsMonitors

Are high-level language constructs that provide equivalent functionality to that of semaphores but are easier to control

Found in many concurrent programming languages

Concurrent Pascal, Modula-3, Java… Functioning not identical...

Can be constructed from semaphores (and vice-versa)

Very appropriate for OO programming

Page 66: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 566

MonitorMonitor

Is a software module containing: one or more procedures an initialization sequence local data variables

Characteristics: local variables accessible only by monitor’s procedures

note O-O approach a process enters the monitor by invoking one of its

procedures only one process can execute in the monitor at any

given time but several processes can be waiting in the monitor

conditional variables

Page 67: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 567

MonitorMonitor

The monitor ensures mutual exclusion: no need to program it explicitly

Hence, shared data are protected by placing them in the monitor the monitor locks the shared data assures sequential use.

Process synchronization is done by the programmer by using condition variables that represent conditions a process may need to wait after its entry in the monitor

Page 68: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 568

Condition variablesCondition variables

accessible only within the monitor can be access and changed only by two

functions: cwait(a): blocks execution of the calling process on condition

(variable) a process can resume execution only if another process executes

csignal(a) csignal(a): resume execution of some process blocked on

condition (variable) a. If several such process exists: choose any one (FIFO or priority) If no such process exists: do nothing

Page 69: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 569

Queues in MonitorQueues in Monitor

Processes await entrance in the entrance queue A

Process puts itself into condition queue cn by issuing cwait(cn)

csignal(cn) brings into the monitor 1 process in condition cn queue

csignal(cn) blocks the calling process and puts it in the urgent queue (unless csignal is the last operation of the process)

Page 70: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 570

Producer/Consumer problem: Producer/Consumer problem: first attemptfirst attempt

Two processes: producer consumer

Synchronization is now confined within the monitor

append(.) and take(.) are procedures within the monitor: are the only means by which P/C can access the buffer

If these procedures are correct, synchronization will be correct for all participating processes

Easy to generalize to n processes

BUT incomplete solution...

Producer:repeat produce v; append(v);forever

Consumer:repeat take(v); consume v;forever

Page 71: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 571

Monitor for the bounded P/C problemMonitor for the bounded P/C problem

Monitor needs to handle the buffer: buffer: array[0..k-1] of items;

needs two condition variables: notfull: csignal(notfull) means that buffer not full notempty: csignal(notempty) means that buffer not

empty needs buffer pointers and counts:

nextin: points to next item to be appended nextout: points to next item to be taken count: holds the number of items in buffer

Page 72: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 572

Monitor for the bounded P/C problemMonitor for the bounded P/C problem

Monitor boundedbuffer: buffer: array[0..k-1] of items; nextin:=0, nextout:=0, count:=0: integer; notfull, notempty: condition; //buffer state

append(v): if (count=k) cwait(notfull); buffer[nextin]:= v; nextin++ mod k; count++; csignal(notempty);

take(v): if (count=0) cwait(notempty); v:= buffer[nextout]; nextout++ mod k; count--; csignal(notfull);

Page 73: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 573

Conclusions on monitorsConclusions on monitors

Understanding and programming are generally easier than for semaphores

Object Oriented philosophy

Page 74: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 574

Message PassingMessage Passing

Is a general method used for interprocess communication (IPC) for processes inside the same computer for processes in a distributed system

Yet another mean to provide process synchronization and mutual exclusion

We have at least two primitives: send(destination, message) receive(source, message)

In both cases, the process may or may not be blocked

Page 75: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 575

Blocking, waitBlocking, wait

Are the sender or received blocked until receiving some sort of answer?

For the sender: it is more natural not to be blocked after issuing send(.,.) (wait for reception)

can send several messages to multiple dest. but sender usually expects acknowledgment of

message receipt (in case receiver fails) For the receiver: it is more natural to be blocked

after issuing receive(.,.) the receiver usually needs the info before proceeding but could be blocked indefinitely if sender process fails

before send(.,.)

Page 76: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 576

Blocking (cont.)Blocking (cont.)

Hence other possibilities are sometimes offered Ex: blocking send, blocking receive:

both are blocked until the message is received occurs when the communication link is

unbuffered (no message queue) provides tight synchronization (rendez-vous)

Indefinite blocking can be avoided by the use of timeouts.

Page 77: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 577

Addressing in message passingAddressing in message passing

direct addressing: when a specific process identifier is used for

source/destination but it might be impossible to specify the

source ahead of time (ex: a print server) indirect addressing (more convenient):

messages are sent to a shared mailbox which consists of a queue of messages

senders place messages in the mailbox, receivers pick them up

Page 78: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 578

Mailboxes and PortsMailboxes and Ports

A mailbox can be private to one sender/receiver pair

The same mailbox can be shared among several senders and receivers the OS may then allow

the use of message types (for selection)

Port: is a mailbox associated with one receiver and multiple senders used for client/server

applications: the receiver is the server

Page 79: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 579

Ownership of ports and mailboxesOwnership of ports and mailboxes

A port is usually owned and created by the receiving process

The port is destroyed when the receiver terminates

The OS creates a mailbox on behalf of a process (which becomes the owner)

The mailbox is destroyed at the owner’s request or when the owner terminates

Page 80: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 580

Message formatMessage format

Consists of header and body of message

control info: sequence numbers error correction codes priority...

Message queuing discipline: varying: FIFO or can also include priorities

Page 81: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 581

Enforcing mutual exclusion with message Enforcing mutual exclusion with message passingpassing

create a mailbox mutex shared by n processes

send() is non blocking receive() blocks when

mutex is empty Initialization: send(mutex,

“go”); The first Pi who executes

receive() will enter CS. Others will be blocked until Pi resends msg.

A process can receive own message

Process Pi:var msg: message;repeat receive(mutex,msg); CS send(mutex,msg); RSforever

Page 82: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 582

The Global ViewThe Global View

Process Pi:var msg: message;repeat receive(mutex,msg); CS send(mutex,msg); RSforever

Process Pj:var msg: message;repeat receive(mutex,msg); CS send(mutex,msg); RSforever

Initialize: send(mutex, go)

Note: mutex can be rec’d by same process that sends ithence process can reenter CS immediately

Page 83: Chapter 5 1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.

Chapter 586

Conclusions on synchro. mechanismsConclusions on synchro. mechanisms

A variety of methods exist, and each method has different variations.

The most commonly used are semaphores, monitors, and message passing.

Monitors and message passing are the easiest to use, closest to programmer’s needs.

Simpler mechanisms can be used to implement more sophisticated ones.

No mechanism prevents in principle deadlocks, starvation, or busy waiting but more sophisticated mechanisms make it easier to avoid them.