Computational Process Networks

This is a research and development release. There may be bugs, and things may change in future releases. If you find this useful or find a bug let us know.



An effort to use doxygen documentation syntax was used throughout. The html pages generated by doxygen are served here.

There is also a tutorial PDF on the basics of using the CPN library, with example code in the directory tutorial_code.

Some details of CPN are also available in Greg Allen's Ph.D dissertation.

The doxygen documentation can be built from the source code by running:

cd /path/to/cpn
doxygen doxygen.conf

The tutorial can be built (requiring LaTeX and Graphviz) by running:

cd /path/to/cpn/tutorial

Library dependencies

  • cppunit for the unit tests (can be disabled)
  • libxml++ for XML parsing (can be disabled)
  • fftw3 for the beamformer example (can be disabled)
  • libvariant for configuration management and data serialization


The unit tests require cppunit. All of the tests are in the test directory.

Changes since last release

  • Moved the Variant class and serializers into a separate library, libvariant.
  • Bug fixes.
  • Added Flush and Reset semantics to the queues

Previous Changes

  • Convert to autotools
  • Convert to use libtool
  • Change default node loading behavior
  • Put project on bitbucket
  • Setup a way to install/uninstall the library into the system with included pkg-config files.
  • Added example of an auxilary library that could be installed along side CPN to add extra nodes.


Two applications are provided with this library. They are RemoteContext and CPNKernel.


This is a loader application which takes a set of command line options and configuration files and loads up a CPN network. This expects that all the nodes can be looked up with the node loader. (See Node Library section below)


This is a realization of a centralized version of the remote context daemon over sockets. See the output to the -h option for details on how to run.

Examples and case studies

These are all located in the examples directory. All applications here support the -h option to gives some documentation how usage.

Seive of Eratosthenes

There are two versions of this, the first is called SimpleSieve and the second is called ThresholdSieve. The code is for these is under examples/SieveOfEratosthenes. Use the -h option to get specific options.

Random Instruction

There are two versions of the random instruction case study. Both are in the examples/RandomInstruction directory. The first version instantiates the random instruction nodes in a single process and is named RandomInstruction. Run with -h to get a list of options.

The second version exercises the remote queue/context functionality. This version is called RemoteRandomInstruction. The -h option gives some details on how to run it. The remote random instruction takes a config file that tells it how to create notes on what processes and what processes exist. See the -h option and the example config configk2n100i100 in the same directory for examples of the configuration file. To run this first run the RemoteContext then run each of the processes. For the example config we might run:

Run on zeus: RemoteContext zeus 12345
Run: RemoteRandomInstruction configk2n100i100 kone zeus 12345
Run: RemoteRandomInstruction configk2n100i100 ktwo zeus 12345

This would run the RemoteContext daemon on zeus then create two instances of the remote random instruction each named kone and ktwo.


There are several implementations in one directory. These provide basic command line driven ways of running the different parts of the beamformer and several different tests. Use the -h option on each after it has been built for options on how to run them.


This is a full blown example project for a node that gets installed along side the CPN library. There are included json config files for the CPNKernel that give an example of what they can do. These nodes use the zlib compression library to implement compression and decompression nodes.

About External Endpoints

External endpoints are a special handle to a queue endpoints that is not associated with a node. This is useful for the case where you want to input or output data to the network of nodes. For example, instantiate some network of nodes, then create two endpoints to be input and output. Then this allows for the application to grab endpoints outside of a node for putting data in and out. One has to be careful though as all the same rules apply for determinism and deadlock. The idea behind this was that CPN could be used in a larger application where CPN is just a library used to compute some intermediate value for the application. One of the design goals in mind while writing CPN was that it should be usable in as many situations as possible.


kernel.CreateExternalWriter("writer name");
... generate queues...
CPN::OQueue<int> out = kernel.GetExternalOQueue("writer name");
while (data) {

kernel.DestroyExternalEndpoints("writer name");

About Function Nodes

These are nodes that can be created by passing a function or function object to the kernel. It is setup with templates to allow for the passing of up to 9 parameters to a function node. The idea here is that sometimes one wants a simple node where writing all the machinery for a full blown node would be overkill. This feature is used in the tests in several places where writing a full node would have been painfully verbose.


void testnode(CPN::NodeBase * node, std::string endpoint) {
    CPN::IQueue<int> in = node->GetIQueue(endpoint);
    ... read from in

in setup do
kernel.CreateFunctionNode("node name", testnode, std::string("endpoint name"));

Node Library

One of the features is dynamic node type loading. The way this works is that there is a node loader class which has a list of places to search for nodes. The first thing the node loader does is look through the symbol table of the program for a symbol which is a mangling of the node type name. If this symbol is found it will call it as a function to get a node factory for that node type. If it is not found then it will look into an internal dictionary to see if some dynamic library can be loaded which will provide the symbol. The way the node loader knows if there is a library it can load is by telling it with a node list file. The node list file has a very simple syntax. There are two kinds of directives, include and defining a node type name and its library. The include is simply the keyword include followed by arbitrary white space then a list of files to include separated by white space. All commands end in a semicolon. The library node type name is the keyword lib followed by white space then the name of the dynamic library to load followed by white space then the mangled node type name and finished with a semicolon. By default the node loader will look into \${prefix}/cpnnodes for files matching *.nodelist and load them as additional node lists.

There are some default nodes contained in the nodelib directory.

Defining A Node

To define a node, subclass CPN::NodeBase. Then somewhere in the implementation file put the macro CPN_DECLARE_NODE_FACTORY(typename, classname);. Note that typename must be a valid as a symbol name. There is also a macro CPN_DECLARE_NODE_AND_FACTORY(typename, classname); which allows one to declare the node and factory all at once and all that is required is a definition of the classname::Process() function. This allows stateless nodes to be created more easily.