====== POM ======
===== Introduction =====
POM (Parallel Object Monitors) is a concurrency abstraction for the coordination of parallel activities over single objects and groups of objects in shared memory systems. It allows a clean separation of the coordination concern from the base application code.
A POM is a monitor defining a //scheduling method// responsible for specifying how concurrent requests should be scheduled, possibly in parallel. A POM also defines a //leaving// method which is executed by each thread once it has executed a request. Such methods are essential to the proposed abstraction as it makes it possible to reuse functional code as it is, adding necessary synchronization actions externally.
When a thread invokes a method on an object controlled by a POM, the thread is blocked and the invocation is reified and turned into a //request// object. Requests are then queued in a //pending queue// until the scheduling method grants them permission to execute. The scheduling method can trigger the execution of several requests; all selected requests are free to execute //in parallel//, and are run by the thread that originated the call. When a thread has finished the execution of a request, it has to run the leaving method before leaving the POM. Note that although requests can be executed in parallel, the scheduling and leaving methods are always executed in mutual exclusion.
===== Usage =====
POM is based on [[Reflex]] and therefore Reflex should be installed and configured prior to using POM. POM can be used through [[#Direct configuration|direct configuration]] or through [[Annotations|annotations]]. In both cases, the [[Scheduler definition|scheduler]] is defined in the same way.
==== Direct configuration ====
Direct configuration consists in explicitly using the POM API in a POM configuration class so as to create the appropriate Reflex links, hooksets and metaobjects. An example of such a configuration can be found in the SVN repository: [[http://pleiad.dcc.uchile.cl/svn/pom/src-tests/reflex/lib/pom/test/bench/Config.java|Config.java]].
The first step is to create a configuration class that extends ''POMConfig'' and override the ''initPOM()'' method:
public class Config extends POMConfig {
protected void initPOM() {
The ''initPOM()'' method must call one of the ''schedule()'' method to specify the scheduling policies (the different variants of the ''schedule'' method are described in details in the Javadoc of the ''POMConfig'' class). In the following, all instances of the ''POMBuffer'' class are scheduled by a single ''POMBufferScheduler'':
schedule("reflex.lib.pom.test.bench.pc.POMBuffer",
"reflex.lib.pom.test.bench.pc.POMBufferScheduler");
}
Finally create a ''main()'' method that sets up Reflex. In the following, the link provider (-lp) is set to be the current configuration class; the scope (--working-set) is reduced to the classes of the ''reflex.lib.pom'' package and its subpackages, and the class that contains the actual ''main()'' method is specified:
public static void main(String[] args) throws Throwable
{
LogLevel.set(LogLevel.VERBOSE);
Run.main(new String[] {
"-lp", Config.class.getName(),
"--working-set", "[+reflex.lib.pom.**]",
"reflex.lib.pom.test.bench.Main" });
}
}
==== Annotations ====
Another, and often easier, way to configure POM is to use annotations. In this case, the ''POMConfig'' class itself can be used as a link provider and the classes and methods to synchronize are marked with annotations:
@POMSyncClass(
scheduler = Scheduler.class,
group = Scheduler.class,
syncAll = false)
public class MyClass
{
@POMSync(category="C1") public void foo() { ... }
@POMSync public void bar() { ... }
public void bar2() { ... }
}
In the above example, the ''MyClass'' class is synchronized by ''Scheduler''. Instances of ''MyClass'' are divided into groups as specified by a ''POMGroupDef'' (in this case, ''Scheduler'' implements ''POMGroupDef'') . The ''syncAll'' attribute of ''POMSyncClass'' indicates that by default no method is synchronized: methods to synchronize are explicitly specified using the ''@POMSync'' attribute. Here the ''foo()'' and ''bar()'' methods are synchronized, while the ''bar2()'' method is not.
==== Scheduler definition ====
The scheduler is responsible for granting requests the permission to execute. A POM scheduler must extend the ''POMScheduler'' class and at least override the ''schedule()'' method; it can also override the ''leave()'' method if necessary.
Example 1: a simple mutual exclusion scheduler.
public class MutualExclusionSched extends POMScheduler {
private boolean working = false;
public void schedule() {
if(!working) working = executeOldest();
}
public void leave(Request req) {
working = false;
}
}
The state of ''MutualExclusionSched'' consists of a boolean variable (''working'') that is true if and only if there is //one// thread executing a method in one of the monitored objects. The scheduling method only grants permission to execute a request when ''working'' is false: the oldest request is given permission to execute through the call to ''executeOldest()''; this method returns a boolean indicating whether some request was actually given permission to execute. The ''leave()'' method updates the value of ''working'' to ''false'' in order to indicate that no request is in execution anymore.
Many more examples are provided in {{bib>pom:ccpe2007|2007-CCPE}}.
===== POM and SOM =====
Sequential Object Monitors, or [[SOM]], is a concurrency abstraction similar to POM but geared towards sequential activities. Actually, a SOM is a particular case of a POM where only one request is executed at a time, and there is only one object controlled by the scheduler. POM provides the ''SOMScheduler'' class for implementing SOM schedulers.
===== Download =====
The source code for POM is available in the SVN repository: [[http://pleiad.dcc.uchile.cl/svn/pom/]].
===== Publications =====