Process Synchronization

Producer/Consumer Problem -- One process produces items (e.g. disk requests, characters, print files) and another process consumes. Shared variables (pseudo-code)
var n: size of buffer buffer: array[ 0 .. n-1 ] of item counter
Algorithm
Producer:
var: put; --where to put next item
repeat
.
produce item
.
while counter == n loop;
buffer[ put ] = item;
put = put + 1 mod n;
counter = counter + 1;
until false

Consumer
var get; --where to get next item
repeat
while counter == 0 loop;
item = buffer[ get ];
counter = counter - 1;
.
consume item
.
until false

How to run concurrently? Problem is shared variables which can be changed. On most machines, the lines "counter = counter +/- 1" will be implemented as

  1. fetch contents of mem location counter and store in register r.
  2. increment contents of register r.
  3. store the contents of register r in mem location counter.

Imagine 2 processes executing sequentially:

   producer A:                  consumer B:         
       .                            .
       .                            .
       .                            .
    fetch   (1)                  fetch    (2)
    inc     (5)                  inc      (3)
    store   (6)                  store    (4)
       .                            .
       .                            .
       .                            .
Assume the instruction are executed in the order given in parentheses (this would happen if, for example process A timed out after executing the fetch, then process B ran, then process A runs again.

Critical Sections

This introduces the idea of a critical section. While A is modifying the shared variable counter, no other process should modify it. If several processes can modify a shared variable then each has one or more critical sections associated with that variable.

The critical section problem is to provide a mechanism with the following properties:

  1. mutual exclusion -- if P1 is executing in the critical section, no other process can execute in that critical section.
  2. progress -- if no process is in the critical section and some processes are waiting to enter, then one will enter.
  3. bounded waiting -- there must be a bound on the number of times any process can enter the critical section if other processes are waiting to enter.

Assume each process is exectuing at nonzero speed, though no assumption is made about relative speeds.

Performance consideration often require that process's time in a critical section will be as brief as possible because of the possibility of blocking other processes.

Assume processes are of form:

repeat forever
.
miscellaneous code
.
enter critical section
code
exit critical section
.
miscellaneous code
.
end

Will look at various methods for entry and exit.

Any real solution will require some type of hardware support. Often the code in a critical section is more complex than a fetch, inc. and store sequence. However, if the task is as simple as protecting a shared variable, this can be done easily (often by turning off the timing interrupt so that the process cannot be interrupted while it is changing the shared variable). A compiler can generate code to support this. Below we assume that if we delcare a variable to be shared, the compiler can generate code to make sure that it is changed without being stopped.


Index Previous Next

Copyright ©2015, G. Hill Price
Send comments to G. Hill Price