An active module is an ordinary module whose instances (copies sharing the same code but different state or data) have computational resources attached (e.g., computation steps shared in a fair fashion).
Active modules provide a high-level model of concurrency suitable for distributed execution (and inter-process communication) that is similar to active objects and actors. Note that Ciao also offers lower-level primitives for concurrency and network-based communication.
Each active module instance is internally composed of a local mailbox for queries (a queue of messages) and a query handler loop. Each active module instance is identified by a unique name (which can be provided or created automatically).
Calls to exported predicates of an active module are enqueued in the mailbox. The query handler loop is a deterministic loop that executes queries sequentially, sending back the results to the caller program (another active module instance) if needed. The composition of the (possibly) multiple answers from the callee and the caller is given be the query protocols defined below.
There exist several query protocols depending on the expected answers of a predicate.
Further details on the semantics and concurrency model:
All communication between active module instances should (in principle) happen through message passing. Instances should not share any global data. Sharing via dynamic/data predicates (or other global mechanisms) is seen as an impure side-effect w.r.t. this model and must be used with care (e.g., caching, hand-made optimizations, etc.).
In a distributed setting active module instances may run on separate nodes that can interchange messages through the network. See actmod_dist for more details about the distribution protocol and how it can be extended.
Using active modules requires the use of the actmod package:
:- module(...,...,[actmod]).
This turns the current module into an active module and enables all the directives and features required to use other active modules.
Predicates exported by an active module can be accessed by other active modules using the use_module/3 declaration with the active option (see below).
Note that the process of using an active module does not involve transferring any code, but rather setting up things so that calls in the module using the active module are executed as remote procedure calls to the active module.
For spawning active module instances (dynamic creation) see actmod_process.
Active modules may implement a main/1 predicate, if they want to receive command-line arguments or use the directive :- dist_node to include a default main/1 for distributed nodes. See actmod_dist for more details.
The following command:
ciaoc simple_server.pl
compiles the simple server example that comes with the distribution (in the actmod/example directory). The simple_client_with_main example (in the same directory) can be compiled as usual:
ciaoc simple_client_with_main
Now, if the server is running when the client is executed it will connect with the server to access the predicate(s) that it imports from it.
An even simpler client simple_client.pl can be loaded into the top level and its predicates called as usual (and they will connect with the server if it is running).
Usage::- use_module(ModSpec,Imports,Opts).
Import from ModSpec the predicates in Imports with options Opts. If Imports is a free variable, all predicates are imported.
Options for use_module/3: