Welcome
»
NERWous C
A Serial Producer / Consumer
This is a Producer / Consumer example written in standard C language:
main () {
int c;
while (c = Produce())
Consume(c);
}
The
main
task works serially. It calls
Produce
to get a value to
c
, then calls
Consume
to consume it. The cycle repeats until there is no more products (with
Produce
returning 0).
A 3-Task NERW Producer / Consumer
Let's apply the NERW model to make the above code concurrent:
main () {
<mel> int store;
<pel> Producer (store);
<pel> Consumer (store);
}
void Producer (<mel> int store) {
int c;
while ( c = Produce() )
<?>store = c;
<?>store = 0;
}
void Consumer (<mel> int store) {
int c;
while ( c = <?>store )
Consume(c);
}
The task
main
creates a
mel
variable,
store
, as the communication channel between the Producer and Consumer. It then creates a task to run the
Producer
code via the
pel
construct, and immediately creates another task to run the
Consumer
code. The task
main
then waits for all the tasks it forks to be terminated.
The
Producer
task keeps producing until
Produce
returns 0. Every time it has a product, it will see if the mel
store
is available for it to deposit the product. By definition, the mel variable has one slot (we will see how to define a multi-slotted mel variable later). If a slower
Consumer
task has not consumed the previous product, the
Producer
will wait at the mel via the <?> construct. Once the deposit to the mel is successful, the
Producer
resumes its
Produce
chore. When it cannot
Produce
any more, it will deposit a 0 value to the mel to alert the
Consumer
task. The
Producer
task then terminates.
The
Consumer
task runs in parallel with the
Producer
task. The two synchronize at the mel variable
store
. If
store
is empty (due to a slower
Producer
) or is locked by the
Producer
while it deposits a new product, the
Consumer
task will wait at the <?> construct. Once it sees a 0-valued product, the
Consumer
task terminates.
With all tasks it forks terminated, the
main
task terminates itself. The application then exits.
A 2-Task NERW Producer / Consumer
Instead of pelling a task to run
Consumer
, the task
main
can run it by itself:
main () {
<mel> int store;
<pel> Producer (store);
Consumer (store);
}
This will save some task resources.