Welcome
» NERWous C
» Mel
Writers Subscriptions
The previous example introduces the
In the beginning, when a mel is created, its writers subscription is undefined. The first producer task that executes a write operation (such as
For each task, the writers subscription is a one-time event. As said above, the first write operation by the task will record its subscription. Any subsequent write operations by the same task will not add another subscription. New subscriptions only occur when new producer tasks access the mel for writing the first time to that mel.
When the task ends, the CHAOS runtime environment will automatically unsubscribe the task from the mel. If the task has a writers subscription, this action will decrease the writers subscription of the mel by 1. A task can also explicitly unsubscribe by invoking the
Any consumer task that accesses the mel entity for reading will receive the writers subscription number from the mel entity. This number is cached locally in the mel proprety,
It is worthwhile to re-emphasize that the
The following example shows the use of the
The
The
Quit vs. Close
The mel close operation is a more drastic and global way for the
The first
Readers Subscriptions
The readers subscription is similar to the writers subscription, but for the read operations.
A mel when first created has its readers subscription undefined. Any task that makes use of the read operation (such as
Any producer task that accesses the mel entity for writing will receive the readers subscription number from the mel entity. This number is cached locally in the mel proprety,
Like the
The following example shows the use of the
Dual Subscriptions
A task can have both readers and writers subscriptions.
We will now modify the example above by introducing an
Quit Attributes
The above implementation of
The same argument applies similarly for the <quit writers> command, any waiting
Astute readers of the
Previous Next Top
Writers Subscriptions
The previous example introduces the
NOWRITERs
exception. This exception makes use of the writers subscription feature of the mel.
In the beginning, when a mel is created, its writers subscription is undefined. The first producer task that executes a write operation (such as
<?>store = 10
) is said to have subscribed to the mel for writing. The writers subscription is now 1. Other producer tasks that come along later will add 1 each to the writers subscription.
For each task, the writers subscription is a one-time event. As said above, the first write operation by the task will record its subscription. Any subsequent write operations by the same task will not add another subscription. New subscriptions only occur when new producer tasks access the mel for writing the first time to that mel.
When the task ends, the CHAOS runtime environment will automatically unsubscribe the task from the mel. If the task has a writers subscription, this action will decrease the writers subscription of the mel by 1. A task can also explicitly unsubscribe by invoking the
quit
operation, as shown in the example below.
Any consumer task that accesses the mel entity for reading will receive the writers subscription number from the mel entity. This number is cached locally in the mel proprety,
writers
. If the consumer has a catch
on the NOWRITERS
exception, several things happen when the consumer does a wait operation for reading. If the writers subscription is 0, the wait is aborted and the consumer task will have the NOWRITERS
exception raised with the mel property writers
updated to 0. If the writers subscription is undefined or greater than 0, the consumer task will stand in the mel queue and continues with the mel read wait process. If the wait becomes successful and the consumer task gets a value, the local mel property writers
is updated to the actual writers subscription number at that time. If during the wait, the writers subscription becomes 0, then the wait is broken and the consumer task will have the NOWRITERS
exception raised with the mel property writers
updated to 0.
It is worthwhile to re-emphasize that the
NOWRITERS
exception is optional. If the reader task does not define a NOWRITERS
exception handler, than even when the mel property writers
is found to be 0, no NOWRITERS
exception will be raised for the task. Such a reader task expects writer tasks to come and go, and there will be periods of times where there are no writers at all to deposit new values. In those times, the reader task simply waits at the mel read wait statement.
The following example shows the use of the
quit
operation, the NOWRITERS
exception, and the writers
property:
main () {
<mel> int store;
<! name="Producer1"> Producer (store);
<! name="Producer2"> Producer (store);
<!> Consumer (store);
}
void Producer (<mel> int store) {
var n = random();
while ( --n ) {
<?>store = Produce();
}
<quit>store;
DoSomethingElse();
}
void Consumer (<mel> int store) {
while (1) {
try {
Consume (<?>store);
printf ("There are %d producers serving me", store<writers>);
}
catch ( store<NOWRITERS> ) {
printf ("No more producers - let's exit the grind");
break;
}
}
printf ("All consumption done");
}
We have two Producers
running the same code. They Produce
a random number of items then stop and DoSomethingElse
. We have one common Consumer
that gets whatever the Producers
generate via the shared mel store
.
The
Consumer
watches for the NOWRITERS
exception. Without it, it will while
loop forever after both Producers
having stopped Produce
'ing.
The
Producer
makes use of the quit
operation to increase concurrency. Without this operation, the unsubscription to the mel store
has to wait for the DoSomethingElse
to be done and the Producer
task to stop execution for the automatic unsubscription to take place. Here, the NOWRITERS
exception will be raised as soon as both Producer
s have quit
tted, and the All consumption done
message can be printed sooner.
Quit vs. Close
The mel close operation is a more drastic and global way for the
Producer
to mark that it is done with the mel store
. If it is used in the above example instead of quit
, the first Producer
that end
s will cause the other Producer
task to get a mel CLOSED
exception on the write operation operation and stop Produce
'ing. The Consumer
task will also get a CLOSED
exception on its read operation operation, forcing it to abort abnormally. The use of close
will prevent Consumer
to consume whatever products the remaining Producer
has left to Produce
.
The first
Producer
that calls quit
will have no impact on Consumer
. The writers subscription of store
will be down to 1, which is still greater than 0, so the NOWRITERS
exception is not raised on Consumer
. When the remaining Producer
also calls quit
or is terminated, then the NOWRITERS
exception is raised and Consumer
can wrap up within the NOWRITERS
exception handler and then ends itself.
Readers Subscriptions
The readers subscription is similar to the writers subscription, but for the read operations.
A mel when first created has its readers subscription undefined. Any task that makes use of the read operation (such as
c=<?>store
) will increase the readers subscription by 1. The readers subscription is a one-time event. Any subsequent read operations by the same task will not add another subscription. When a subscribed task calls quit
or has stopped running, the readers subscription is decremented by 1.
Any producer task that accesses the mel entity for writing will receive the readers subscription number from the mel entity. This number is cached locally in the mel proprety,
readers
. Any producer task that has the NOREADERS
exception set up, will have this exception raised when it detects that the readers subscription has become 0.
Like the
NOWRITERS
exception, the NOREADERS
exception is optional. If the writer task does not define a NOREADERS
exception handler, than even when the mel property readers
goes down to 0, no NOREADERS
exception will be raised for the writer task. Such a writer task expects reader tasks to come and go, and there will be periods of times where there are no readers to empty the mel buffers so that it can deposit new products. In those times, the writer task just waits at the mel write wait statement.
The following example shows the use of the
quit
operation, the NOREADERS
exception, and the readers
property:
main () {
<mel> int store;
<!> Producer (store);
<! name="Consumer1"> Consumer (store);
<! name="Consumer2"> Consumer (store);
}
void Producer (<mel> int store) {
while (1) {
try {
<?>store = Produce();
printf ("There are %d consumers serving me", store<readers>);
}
catch ( store<NOREADERS> ) {
printf ("No more consumers - let's exit the grind");
break;
}
}
printf ("All consumption done");
}
void Consumer (<mel> int store) {
var n = random();
while ( --n ) {
Consume (<?>store);
}
<quit>store;
DoSomethingElse();
}
We have above 2 Consumer
tasks that Consume
a random number of produced items, before quit
ting. Once both Consumer
tasks have quit
ted, the readers subscription to the mel store
becomes 0, causing the NOREADERS
exception to be raised, allowing Producer
to wrap up.
Dual Subscriptions
A task can have both readers and writers subscriptions.
We will now modify the example above by introducing an
Inspector
task that randomly withdraws the next produced item from the pipeline, examines it, and puts it back for consumption if it passes inspection.
main () {
<mel> int store;
<!> Producer (store);
<! name="Consumer1"> Consumer (store);
<! name="Consumer2"> Consumer (store);
<!> Inspector (store);
}
void Inspector (<mel> int store) {
int c;
while ( IsMyShift() ) {
c = <?>store; // withdraw product from pipeline
if ( !Examine (c) ) { // examine it
printf ("Stop the line -- value [%d] does not pass inspection", c);
<close>store;
return;
}
printf ("Value [%d] is good for consumption", c);
<?>store = c; // put it back to pipeline
sleep (random()); // to do the inspection randomly
}
<quit>store;
WriteShiftReport ();
}
Because the Inspector
has a read operation and write operation, it has both the readers and writers subscriptions. At the end of its shift, it calls quit
to unsubscribe to both subscriptions. However, during its shift, if it detects a bad product, it will close
the mel, triggering CLOSED
exceptions to all running processes that access the mel store
. Since neither Producer
nor Consumer
has code to handle the CLOSED
exception, this exception will abort those tasks. With all tasks not ended, the program also exits, causing the "line to be stopped" just as Inspector
wants it.
Quit Attributes
The above implementation of
Inspector
has a big flaw. It prevents Producer
to detect the NOREADERS
exception, since Inspector
itself is a readers subscriber. As long as Inspector
is still in its shift, it will prevent the readers subscription number to go to 0 even if all the Consumer
tasks have already quit
tted. Let's modify Inspector
:
void Inspector (<mel> int store) {
int c;
while ( IsMyShift() ) {
c = <?>store; // withdraw product from pipeline
<quit readers>;
if ( !Examine (c) ) { // examine it
printf ("Stop the line -- value [%d] does not pass inspection", c);
<close>store;
return;
}
printf ("Value [%d] is good for consumption", c);
<?>store = c; // put it back to pipeline
<quit writers>;
sleep (random()); // to do the inspection randomly
}
WriteShiftReport ();
}
After a read operation, Inspector
unsubscribes to the readers subscription; and after a write operation, to the writers subscription. If all Consumer
tasks have quit
ted, and there is a Producer
waiting at the mel queue for a buffer slot to free up so it can deposit its product, the <quit readers> command from Inspector
will allow the readers subscription number to go to 0. This will relieve Producer
from waiting and the NOREADERS
exception can be raised.
The same argument applies similarly for the <quit writers> command, any waiting
Consumer
tasks and their NOWRITERS
exception handling.
Astute readers of the
Inspector
code above may claim that we would not need the attribute readers
and writers
to the quit
operation. And they are right. When Inspector
starts, it does not have any subscriptions. On its first read operation statement (c = <?>store;
), it gains a readers subscription. Since it has only one subscription, the more generic <quit>
statement will generate the same result as the specific <quit readers>
statement used here. The same logic applies for the <quit writers>
statement.
Previous Next Top
No comments:
Post a Comment