TANNENBAUM SECTION 2.3 INTERPROCESS COMMUNICATION3 OPERATING SYSTEMS.

Post on 17-Jan-2016

220 views 1 download

transcript

TANNENBAUMSECTION 2.3

INTERPROCESS COMMUNICATION3

OPERATING SYSTEMS

PRODUCER/CONSUMERBOUNDED BUFFER

• Producer puts items into a buffer• Consumer removes items from buffer• Producer issue: attempts to put an item in a full

buffer• Consumer issue: attempts to remove an item

from an empty buffer

PRODUCER/CONSUMER MODEL 1

prod_cons1(){ const int N = const int N = 100;100; int count = 0; int count = 0;

parbeginparbegin

{{

producer();producer();

consumer();consumer();

}}

parendparend

}}

producer()producer()

{{

int item;int item;

while(1)while(1)

{{ item = make_item(); if (count == N) sleep(); add(item); ++count; if (count == 1) wakeup(consumer); }}

consumer()consumer()

{{

int item;int item;

while(1)while(1)

{{ if (count == 0) sleep(); --count; if (count == (N – 1)) wakeup(producer) take(item) }}

ACCESS TO COUNTIS UNCONSTRAINED

1. buffer is empty2. consumer tests count3. context-switch before sleep4. producer puts an item in the buffer5. increments count to 16. tries to wakeup consumer, but consumer is not

asleep7. produces goes on filling the buffer then goes to

sleep8. consumer runs and goes to sleep9. Could be solved with either peterson or tsl

SEMAPHORE

• ADT proposed by Dijkstra• composed of a single member variable and two

uninterruptible operationssemaphore• variable, s, guards mutex gate• down(s) • inspects s• if s== 0, there is a process in CS• decrements s

• up(s)• increments s

SEMAPHORES COME IN TWO FLAVORS

• Spinlocks: implemented with TSL, are either set or unset• Counting Semaphores: use sleep/wakeup

SPINLOCK SEMAPHORE

class spinlock{ private int s; public: spinlock() { s = 1; }

void down() //uninterruptible { while (s== 0); --s;}

void up() { ++s; }

void unset() //used for synchronization { --s;} };

N-PROCESS EXAMPLE

N_Process(){ spinlock spin;

parbeginparbegin

{{

proc0();proc0();

proc1();proc1();

}}

parendparend

}}

//All N processes look //All N processes look like like

//this//this

proc_0proc_0

{{

while(1)while(1)

{{ spin.down(); cs(); spin.up(); }}

• proc0 runs and calls down

• S == 1, so s is decremented to 0

• Enter CS• proc1, calls down,

fails test and sits in loop

• proc2, calls down, fails test and sits in loop

• proc0 runs, finishes CS, calls up to increment s

• proc2 runs, passes while test, decrements s, leaves down, enters CS

SPINLOCK CAN SYNCHRONIZE PROCESSES. PROC0 BEFORE PROC1

synch(){ spinlock spin; spin.unset();

parbeginparbegin

{{

proc0();proc0();

proc1();proc1();

}}

parendparend

}}

proc0proc0

{{ cs(); spin.up(); }

proc1proc1

{{ spin.down() cs()}

PROC0 CAN’T CONSUME Y UNTIL PROC1 PRODUCES ITPROC1 CAN’T CONSUME X UNTIL PROC0 PRODUCES IT

synch(){ spinlock s1, s2; s1.unset(); s2.unset();

parbeginparbegin

{{

proc0();proc0();

proc1();proc1();

}}

parendparend

}}

proc_0proc_0

{{

while(1)while(1)

{{

produce(x);produce(x);

s1.up();s1.up();

s2.down();s2.down();

consume(y);consume(y);

}}

}}

proc_1proc_1

{{

while(1)while(1)

{{ s1.down(); s1.down();

consume(x);consume(x);

produce(y);produce(y);

s2.up();s2.up();

}}

}}

Demonstrate with a table: s1.s s2.s x y

COUNTING SEMAPHORES

• Instead of busy-wait, process goes to sleep• Process executing up operations wakes sleeping

processes• We have to keep track of which processes are

sleeping on a semaphore because they don’t test themselves (as in busy-wait)• Include with our class a pointer to a linked list of

pointers to process control blocks

pc1 p2 p3 pn

P ...

COUNTING SEMAPHORES

Class Semaphore{ private: int s; pcb_list_lst; public: Semaphore(int value) { s = value; lst == NULL; }

down() { s--; if (s < 0) { l.add(this); sleep(); } }

up() { pcbptr* p; s++; if (s <= 0) { p = lst.delete() wakeup(p); }

N PROCESS SEMAPHORE EXAMPLE

cnt_sem(){ Semaphore s(1); parbegin { proc0(); ... procn-1(); } parend

procj(){ while(1) { S.down(); crit_sect(); S.up(); }}

SCENARIO

1. proc0() runs, calls down: value == 0, enters CS

2. proc1() runs, calls down: value == -1, fails test and blocks

3. proc2() runs, calls down: value == -2, fails test and blocks]

4. proc0() runs, finished CS, calls up: value == -1, removes p1 from sleep list, wakes up p1

lst p1

lst p1 p2

p1lst

PRODUCER-CONSUMERWITH SEMAPHORES

• Recall PC required two variables: count, collection of buffer slots item is to put into or extracted from• Both must be protected• Solution with three semaphores• empty: counts empty buffer slots, initially N• full: counts full buffer slots, initially 0• mutex: controls access to buffer, initially 1

PRODUCER-CONSUMER MODEL 2

prod_cons2(){ SemaphoreSemaphore

mutex(1),mutex(1),

empty(100),empty(100),

full(0);full(0);

parbeginparbegin

{{

prod();prod();

cons();cons();

}}

parendparend

}}

producer()producer()

{{

int item;int item;

while(1)while(1)

{{ item = make_item(); empty.down(); mutex.down(); add(item); mutex.up(); full.up(); }}

consumer()consumer()

{{

int item;int item;

while(1)while(1)

{{

full.down();full.down();

mutex.down();mutex.down();

take(&item);take(&item);

mutex.up();mutex.up();

empty.up();empty.up(); }}

SCENARIOS

#1•consumer runs: value == -1, blocks on full•producer runs: dec empty, dec mutex, enters cs, inc mutex, inc full full.s == 0, wakes up consumer

#2•Suppose full.s == 98, empty.s == 2, mutex.s == 1•producer runs: dec empty (so empty.s == 1), dec mutex (so mutex.s == 0), enters cs•consumer runs: dec full (so full.s == 97), dec mutex (so mutex.s == -1) consumer blocks on mutex•producer runs: inc mutex (so mutex.s == 0), wakes up consumer, inc full (so full.s == 98)•consumer runs: enters cs, inc mutex (so mutex.s == 1), inc empty (so empty.s == 2)

Semphore values: full.s == 98, empty.s == 2, mutex.s == 1Both Producer and consumer have run to completion. Semaphore values are as they were in the beginning

A TRAP

• Suppose we wrote producer this way:producer(){ int item; while(1) { item = make_item(); //order of mutex and empty shifted mutex.down(); empty.down(); add(item); mutex.up(); full.up(); }}

SUPPOSE WE WROTE THE PRODUCER LIKE THIS

• Suppose we wrote producer this way:producer(){ int item;

while(1) { item = make_item(); //order of mutex and empty shifted mutex.down(); empty.down(); add(item); mutex.up(); full.up(); }}

• producer runs: 100 times, empty.s == 0

• producer runs: dec mutex (mutex.s == 0)

dec mutex and blocks• consumer runs: dec mutex and blocks

Problem: producer claimed mutex flag before it was needed

CORRECT SOLUTIONS

• Peterson• software• two processes• busy-wait

• TSL• hardware• N processes• busy-wait

• Spinlock Semaphore• Hardware• N processes• busy-wait

• Counting Semaphore• Hardware• N processes• sleep/wakeup

BUILDING A MODEL OF PRODUCER/CONSUMER

Primitives•pipes: direct communication link between two linux processes•semaphore system calls in linux