25.11.2014 Views

Algorithms and Data Structures

Algorithms and Data Structures

Algorithms and Data Structures

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

N.Wirth. <strong>Algorithms</strong> <strong>and</strong> <strong>Data</strong> <strong>Structures</strong>. Oberon version 31<br />

We are now able to express the buffer module in a form that functions properly when used by individual,<br />

concurrent processes:<br />

MODULE Buffer;<br />

IMPORT Signals;<br />

CONST N = 1024; (*buffer size*)<br />

VAR n, in, out: INTEGER;<br />

nonfull: Signals.Signal; (*n < N*)<br />

nonempty: Signals.Signal; (*n > 0*)<br />

buf: ARRAY N OF CHAR;<br />

PROCEDURE deposit (x: CHAR);<br />

BEGIN<br />

IF n = N THEN Signals.Wait(nonfull) END;<br />

INC(n); buf[in] := x; in := (in + 1) MOD N;<br />

IF n = 1 THEN Signals.Send(nonempty) END<br />

END deposit;<br />

PROCEDURE fetch (VAR x: CHAR);<br />

BEGIN<br />

IF n = 0 THEN Signals.Wait(nonempty) END;<br />

DEC(n); x := buf[out]; out := (out + 1) MOD N;<br />

IF n = N-1 THEN Signals.Send(nonfull) END<br />

END fetch;<br />

BEGIN n := 0; in := 0; out := 0; Signals.Init(nonfull); Signals.Init(nonempty)<br />

END Buffer.<br />

An additional caveat must be made, however. The scheme fails miserably, if by coincidence both<br />

consumer <strong>and</strong> producer (or two producers or two consumers) fetch the counter value n simultaneously for<br />

updating. Unpredictably, its resulting value will be either n+1, or n-1, but not n. It is indeed necessary to<br />

protect the processes from dangerous interference. In general, all operations that alter the values of shared<br />

variables constitute potential pitfalls.<br />

A sufficient (but not always necessary) condition is that all shared variables be declared local to a<br />

module whose procedures are guaranteed to be executed under mutual exclusion. Such a module is<br />

called a monitor [1-7]. The mutual exclusion provision guarantees that at any time at most one process is<br />

actively engaged in executing a procedure of the monitor. Should another process be calling a procedure of<br />

the (same) monitor, it will automatically be delayed until the first process has terminated its procedure.<br />

Note. By actively engaged is meant that a process execute a statement other than a wait statement.<br />

At last we return now to the problem where the producer or the consumer (or both) require the data to<br />

be available in a certain block size. The following module is a variant of the one previously shown,<br />

assuming a block size of N p data elements for the producer, <strong>and</strong> of N c elements for the consumer. In these<br />

cases, the buffer size N is usually chosen as a common multiple of N p <strong>and</strong> N c . In order to emphasise that<br />

symmetry between the operations of fetching <strong>and</strong> depositing data, the single counter n is now represented<br />

by two counters, namely ne <strong>and</strong> nf. They specify the numbers of empty <strong>and</strong> filled buffer slots respectively.<br />

When the consumer is idle, nf indicates the number of elements needed for the consumer to proceed; <strong>and</strong><br />

when the producer is waiting, ne specifies the number of elements needed for the producer to resume.<br />

(Therefore ne + nf = N does not always hold.)<br />

MODULE Buffer;<br />

IMPORT Signals;<br />

CONST Np = 16; (*size of producer block*)

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!