Pages

Sunday, May 20, 2012

Wait Exception (NOMORE / NOOUT / NOIN)

In the previous Producer/Consumer example, the Producer indicates that it is done producing by generating a NULL item as the last item. Many Producers are not that nice. When they are done producing, they just terminate. What happens to the Consumer then? Will it wait forever? Let's look at this new code:
main() {
    pel Producer() p;
    pel Consumer(p);
}
(mel item val) Producer () {
    while ( !timeToPunchOut() )
      ?val = produce();
}
void Consumer (Producer p) {
    try {
      while ( 1 )
          consume(?p!val);
    }
    catch (p!NOMORE){
      printf ("Producer has done producing. I go home too");
    }
}
Here, the Consumer keeps consuming until its wait for the mel val of the pel p fails due to the NOMORE pel exception. This exception is raised by the Producer p as it terminates (normally or abnormally). This allows the Consumer to clean itself up (here by printing a message) and terminate too. When both Producer and Consumer have terminated, the whole program terminates.

Now, let us look at the reverse problem, where the Consumer terminates before consuming all the produced items. The Producer keeps producing and deposits into its mel variable val, which acts like a buffer between the Producer and Consumer. If the mel val is full and cannot accept any more items, the Producer then waits at the ? for the Consumer to clear the mel val. If the Consumer has terminated (normally or abnormally), the Producer will wait forever. To break out of such potentially infinite wait, the Producer can check for the NOOUT mel exception:
(mel item val) Producer () {
    try {
        while ( !timeToPunchOut() )
           ?val = produce();
    }
    catch (val!NOOUT) {
        printf ("Consumer has done consuming. I go home too");
    }
}
The NOOUT mel exception is raised when there is no reader subscribing to the mel and the mel buffer stays full for some time (this "some time" is configurable).

There is a corresponding NOIN mel exception for the Consumer to check in case there are no Producer subscribing to the mel to deposit new values. Let's rewrite the example so that we now have one Consumer but two Producers:
main() {
    mel int Val;
    pel Producer1();
    pel Producer2();
    pel Consumer();
}
void Producer1 () {
    for (int i=0; i<10; ++i)
       ?Val = produce();
}
void Producer2 () {
    for (int i=0; i<70; ++i)
       ?Val = produce();
}
void Consumer () {
    try {
       while ( 1 )
           consume (?Val);
     }
     catch (Val!NOIN) {
      printf ("No more producers");
     }
}
The mel Val is now used by both Producers and the single Consumer. Producer1 produces 10 times then terminates. Producer2 does 70 times and terminates. After both of them have terminated, the Consumer will wait forever at the ?Val. Here the Consumer protects itself from a forever wait by checking the NOIN mel exception. This exception is raised by the run-time environment when it detects that there are no pel processes that register to produce for the mel variable Val for some time (this "some time" is configurable).

Thursday, May 10, 2012

Basic Pel and Mel

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.

Monday, May 7, 2012

NERWous C

Welcome

NERWous C is an embodiment of the NERW Concurrency Model using the C language as the base language. NERWous stands for "NERW on utopian systems" since NERWous C currently exists only as a thought exercise.

The purpose of NERWous C is to explore a programming syntax that exposes the capabilities of the NERW Concurrency Model. It answers the question -- how to "easily" write a program based on this reference model. Writing a concurrent program is hard, making it easy is many times harder.

There is an abundance of ways to write a concurrent program. Each concurrent language or extension has its own syntax; you would need more than your fingers and toes to count them. Let NERWous C add another one, which is different from the others. NERWous C's approach is not object oriented like many contemporary concurrent languages; instead, it is procedural and mimics the HyperText Markup Language (HTML):
  1. It uses angle brackets (< and >) to encapsulate NERW-related facilities, preserving as much as possible the existing logic of a program. A simple serial C program could be made concurrent by sprinkling here and there various angle-bracketed NERWous C constructs.
     
  2. It offers attributes in most angle-bracketed NERWous C constructs. Many of these attributes are supported in a relaxed manner, like in the HTML language. If the underlying CHAOS runtime supports them, they will be executed in the optimal manner that the programmer intends; otherwise, their default behavior will allow the program to continue in a strapped and stripped state.
In this chapter:


Previous Next Top

Sunday, May 6, 2012

The Network Element (Nerw)

Welcome » The NERW Reference Model

The fourth element of the NERW Reference Model is the network element (or nerw). Its purpose is to link the cels together. The word "nerw" stands for "network for execution, read and write". Execution applies to the pels, the read and write operations apply to the mels. Note that when used to denote the network element, the term "nerw" is not capitalized. When used to represent the reference model, the term "NERW" is fully capitalized.

The nerw cannot be directly accessible by a program using the NERW Concurrency Model. Like the universe, it is just there. It is "something" that exists to permit pels and mels to access other pels and mels residing in other cels.


Previous Next Top

The Computer Element (Cel)

Welcome » The NERW Reference Model

The purpose of the computer element (or cel) is to abstract the physical entity that hosts the processing element (pel) and/or the memory element (mel).

Certain cels can host only processing elements. For example, a thread in a thread pool is a cel that can only host pel tasks. On the other hand, the cel representing a communication channel only supports messaged mels. There are also cels that can host both execution and storage elements. A transputer with its embedded microprocessor and integrated memory is such an example.

Via the cel properties, a NERW programmer can access the underlying hardware or software entity that actually provides the hosting facility. The programmer can also override the default CHAOS assignment, and specify a particular cel when declaring a pel or mel variable in a NERW program.

Besides providing a hosting abstraction to pels and mels, the cels also act as communicating nodes over an abstract network called the nerw.


Previous Next Top

Tuesday, May 1, 2012

The Memory Element (Mel)

Welcome » The NERW Reference Model

While the first essence of concurrent computing is the existence of multiple processing elements (or pels), the second essence is for these pels to exchange information in order to achieve some common goal set by the application. The state-of-the-art has an abundance of methods to support the sharing of this information between execution entities. We have shared memories, message passing, rendez-vous, ports, portals, pipes, tuples, channels, extends, distributed objects, locks-and-monitors, transactional memory and more. The NERW reference model abstracts all these methods into a basic concept, the memory element or mel.

The presence of the term "memory" in the mel name does not mean that the NERW model requires physical "shared memory". Shared memory is just one way to implement shared information. Another way is to locally cache the shared information and broadcast updates for everybody to synchronize. Yet another way is to centralize the shared information into a server and have clients send messages to request access. And there are many other ways to pass around shared information, as identified in the previous paragraph.

While the mel represents the logical aspect of shared information, this information must physically reside somewhere. The physical locale is provided by the NERW element cel. Like the pel, a NERW programmer usually does not need to know where a mel resides -- the CHAOS runtime will take care of this task behind the scene. In cases the programmer needs to know, the NERW reference model allows a programmer to specifically assign a cel locale to a mel. A cel may represent a huge hard drive, a fast solid-state drive, a faster RAM disk, or special video memory; and shared mel data can be assigned to these cels for special-purposed processing.

A cel can support a single mel or multiple mels, depending on the hardware support. A cel can be specialized to support only mels, or can be generic to host both pels and mels. For example, a personal computer (PC) can be viewed as a cel that has both pels (CPU and thread-supporting OS) and mels (RAM and hard drives).

An implementation of the CHAOS runtime can support different types of mels. For example, a system may support physical shared memory for local processes, and communicating channels for networked processes. At the conceptual level, they are the same: they facilitate shared information, of which the NERW Concurrency Model abstracts as mels.

Mel Implementations

See Mel in NERWous C.


Previous Next Top