Pages

Saturday, March 30, 2013

NOTHING Mel Exception

Welcome » NERWous C » Exceptions

The NOTHING mel exception is the ying-yang of the NOROOM exception. While NOROOM checks if the mel buffer is full, the NOTHING exception is raised when the mel buffer is empty. Like NOROOM, the NOTHING is raised immediately by the application itself when it accesses the mel variable via the wait expression ?.

The NOTHING exception has the same relationship with the NOIN exception as between NOROOM and NOOUT exceptions. While NOTHING and NOIN both check that the mel buffer does not have any product, the NOIN exception is raised by the run-time environment after a configurable amount of time to instill confidence that no Producers will fill the buffer again. As said previously, the NOTHING is raised by the application immediately upon detection of the empty condition.

Let now rewrite the Producer / Consumer example to have two Producers and one Consumer:
main() {
    pel Producer() p1;
    pel Producer() p2;
    pel Consumer (p1, p2) c;
}
(int mel val) Producer () {
    int product;
    for (int i=0; i<10; ++i)
       ?val = produce();
}
void Consumer (pel Producer p1, pel Producer p2) {
    while ( 1 )
        try {
           consume (?p1!val);
        }
        catch (p1!val!NOTHING) {
           consume (?p2!val);
        }
     }
}
The Consumer will first try to get the product from the Producer p1. If this Producer does not have a product ready yet, the NOTHING exception is raised on its mel return port, and Consumer instead of waiting for p1, now attempts to get a product out of the other Producer, p2.

In the above example, if p2 also does not have a product, the Consumer is stuck waiting for it, even if by that time the first Producer, p1 has a product out. To allow the Consumer to keep checking both Producers until it gets a product from any of them, we can rewrite the Consumer:
void Consumer (pel Producer p1, pel Producer p2) {
    while ( 1 )
        consume ( (?p1!val NOTHING ?p2!val) );
 }
One flaw on the above code is that when both Producers have terminated, the Consumer keeps checking ad infinitum. To break out of such loop, the Consumer must also check for the NOIN exception:
void Consumer (pel Producer p1, pel Producer p2) {
    while ( 1 ) {
      try {
        consume ( (?p1!val NOTHING ?p2!val)<somebody_give_me> );
      } catch (somebody_give_me!NOIN) {
          printf ("Both Producers have terminated. I go home too.");
          break;    // out of while loop
      }
    }
 }
Here, the Consumer checks ?p1!val first. If this mel port has NOTHING, it checks ?p2!val. If this mel port also has NOTHING, it goes back to check ?p1!val. This continuous checking is programmatically tagged with the tag somebody_give_me. This tagged checking continues until either Producers has a product for the Consumer, or a NOIN condition has been raised on both Producer mel ports.

We can pass an array of many Producers to the Consumer,too:
void Consumer (pel Producer p[]) {
    while ( 1 ) {
      try {
        consume ( (?p!val NOTHING)<somebody_give_me> );
      } 
      catch (somebody_give_me!NOIN) {
          printf ("All Producers have terminated. I go home too.");
          break;    // out of while loop
      }
    }
}


If in the above example, the first Producer in the array is somehow special, we can specifically watch for its termination in addition to all Producer terminations:
void Consumer (pel Producer p[]) {
    while ( 1 ) {
      try {
        consume ( (?p!val NOTHING)<somebody_give_me> );
      } 
      catch (?p[0]!val!NOIN) {
          printf ("The leader Producer has terminated. I follow the leader and go home.");
          break;    // out of while loop
      }
      catch (somebody_give_me!NOIN) {
          printf ("All Producers have terminated. I go home too.");
          break;    // out of while loop
      }
    }
}

No comments:

Post a Comment