/**
<html>
<title> Semaphore Example : Mutual Exclusion / Synchronization in DLP </title>
<body bgcolor=white>
<a name=top>
<hr>

<h2> Mutual Exclusion / Synchronization in DLP </h2>

<ul>
<li> <a href="#intro"> Introduction </a>
<li> <a href="#synchr"> Mutual Exclusion and Synchronization </a>
<li> <a href="#rendez"> Conditional Rendez-vous </a>
<li> ....
<li> <a href="#references"> References </a>
<li> <a href="#example"> Example </a>
</ul>

<a name=intro>
<hr>
<h2> Introduction </h2>

The core language of DLP [<a href="#references">Eliens</a>] is similar
to Prolog
[<a href="#references">Bratko</a>],
[<a href="#references">Clocksin</a>],
[<a href="#references">Online</a>] :
logical variables, unification, and backtracking are the basic language
characteristics of DLP. In addition to these Prolog-like language constructs,
the language supports multi-threaded objects, non-logical object variables
and conditional communication by rendez-vous.
As an illustration, this overview shows how a <a href="#semaphore">(binary)
semaphore</a> may be implemented by means of a <a href="#rendez">(conditional)
rendez-vous</a> in DLP. Although the implemention of a lower-level
synchronization primitive by means of a higher-level one is rather
straightforward, it illustrates several ways a rendez-vous may be used to
express synchronization between active objects.
For a slightly more complex example of multi-threaded objects and the
<i>rendez-vous</i> take a look at the <a href="pxbuff.html">active bounded
buffer</a> source code.

<a name=synchr>
<hr>
<h2> Mutual Exclusion / Synchronization </h2>

Multi-threaded objects require some sort of mutual exclusion in order
to keep their internal state consistent : active objects that are
allowed to access a common resource without mutual exclusion, may leave
the resource in an inconsistent state.
Many mutual exclusion and synchronization mechanisms have been designed
and their abstraction level is illustrated by the way they solve a number
of classical mutual exclusion problems, e.g. the <i>bounded buffer</i>,
<i>readers - writers</i>, and <i>dining philosophers</i> problems. A so
called <i>(binary) semaphore</i> is one of the lowest-level mechanisms
of all known mutual exclusion concepts. Examples of mechanisms at a
higher-level (than a binary semaphore) are <i>condition variables</i>
(wait / signal, wait / notify), <i>critical regions</i>, <i>monitors</i>,
Ada's <i>rendez-vous</i>, and blocking <i>message passing</i>
[<a href="#references">Andrews</a>], [<a href="#references">Ben-Ari</a>].
<br>
Higher-level synchronization techniques are implemented by means of
lower-level mechanisms. As mentioned, lower-level concepts may be
implemented by higher-level constructs in a straightforward way : their
implementation often looks somewhat artificial as is the case in the
example below.

<a name=semaphore>
<br>
<br>The (binary) semaphore concept is based on railroad signposts and
consists of two operations : <i>lock</i> and <i>unlock</i>. We prefer
the names <i>lock</i> and <i>unlock</i> because they're close to the
POSIX Threads terminology (pthread_mutex_lock, pthread_mutex_trylock,
pthread_mutex_unlock); they express in a more intuitive way what the
operations actually do. Originally semaphore operations, as proposed
by [<a href="#references">Dijkstra</a>], were called "<i>p</i>" and
"<i>v</i>" (Dutch for : passeren / vrijgeven).
As shown in the pseudo code below, the <i>lock</i> and <i>unlock</i>
primitives delimit a critical piece of code for which mutual exclusion
is required :
<pre>
	....
	sema <- lock
	/* critical */
	sema <- unlock
	....
</pre>
The invocation of a <i>lock</i> operation will block the invoking
thread in case another thread has already executed the <i>lock</i>
operation of the corresponding semaphore, otherwise the current
thread is allowed to continue its execution immediately. After acquiring
the lock, a thread has exclusive access to the code fragment
denoted as "critical". When the critical work is done, a thread executes
the corresponding <i>unlock</i> operation : this will unblock <i>one</i>
of the (possibly many) other threads that are waiting as the result of
their own <i>lock</i> invocation.

<a name=rendez>
<hr>
<h2> Conditional Rendez-vous </h2>

<br>A (conditional) rendez-vous in DLP is expressed by means of a so
called <i>accept</i> statement. An accept statement specifies a
disjunction of one or more accept expressions :
<pre>
	AcceptStatement ::=
		accept(AcceptExpression1, .... , AcceptExpressionN)
</pre>
A single accept expression defines a method that an object is willing
to accept. In addition, an accept expression allows for the specification
of a conjunction of conditions and / or the actual code of the method :
<pre>
	AcceptExpresssion ::=
		AcceptMethod						[AE.1]
	or	AcceptMethod ==> MethodBody				[AE.2]
	or	AcceptMethod <== [ MethodGuard ]			[AE.3]
	or	AcceptMethod <== [ MethodGuard ] ==> MethodBody		[AE.4]
	;;
</pre>
In <i>AcceptExpression</i> [AE.1] and [AE.3], the <i>AcceptMethod</i> should
be a callable method. In [AE.2] and [AE.4], the code of <i>AcceptMethod</i>
is specified in the <i>MethodBody</i>, i.e. there is no explicit
<i>AcceptMethod</i> method called in the current object hierarchy.
An <i>AcceptMethod</i> and <i>MethodGuard</i> have one of the following forms :
<pre>
	AcceptMethod ::=
		method
	or	method(Arg1, ..., ArgN)
	;;

	MethodGuard ::=
		Condition
	or	Condition1, ..., ConditionN
	;;
</pre>
A method invocation like "<i>Obj <- method(...)</i>" will be accepted by
an active object "<i>Obj</i>" when both "<i>method(...)</i>" unifies with
one of the <i>AcceptMethod</i> entries of the accept statement in
"<i>Obj</i>" and the (optional) corresponding <i>MethodGuard</i> holds.
<br>In case a particular method has been accepted (a rendez-vous has taken
place), other threads that are invoking a method concurrently, will be
blocked until the previously accepted method has delivered its (first)
solution. After returning its solution, other method calls may be accepted,
depending on the specified accept expressions in the accept statement of
"<i>Obj</i>".

<a name=references>
<hr>

<h2> References </h2>

<ul>
<li> [Andrews] G.R. Andrews, Concurrent Programming : Principles and
     Practice, Addison-Wesley.
<li> [Ben-Ari] M. Ben-Ari, Principles of Concurrent and Distributed
     Programming, Prentice Hall.
<li> [Bratko] I. Bratko, PROLOG Programming for Artificial Intelligence,
     Addison-Wesley.
<li> [Clocksin] W.F. Clocksin, C.S. Mellish, Programming in
     Prolog, Springer-Verlag.
<li> [Dijkstra] Edsger Wybe Dijkstra, Cooperating Sequential Processes,
     Technical Report EWD-123,
     <br> University of Eindhoven, The Netherlands, 1965, (
     <a href="http://www.cs.utexas.edu/users/EWD/indexBibTeX.html"> 1968 copy </a>,
     <a href="../copy/EWD123.pdf"> local copy </a>).
<li> [Eliens] A. Eliens, DLP : A Language for Distributed Logic
     Programming, Wiley.
<li> [Gallmeister] Bill O. Gallmeister, Posix. 4 : Programming for the
     Real World, O'Reilly & Associates.
<li> [Online] The <a href="http://www.ifcomputer.com/PrologCourse/">
     Practical Standard Prolog Courseware Initiative </a> tutorials (
     <a href="../copy/online.html">local copy</a> ).
</ul>

<a name=example>
<hr>

<h2> Example </h2>

 Object <i>semaphore1</i> below has three methods : <i>lock</i>,
<i>unlock</i>, and the active object constructor <i>semaphore1</i>. The first
accept statement, <i>accept(lock)</i>, states that object <i>semaphore1</i>
is only willing to accept a <i>lock</i> method call. When such a call is
accepted other threads will block in case they invoke a <i>lock</i>
concurrently. After <i>accept(lock)</i> object <i>semaphore1</i> only accepts
an <i>unlock</i> as expressed by the <i>accept(unlock)</i> statement. A thread
for which <i>lock</i> is accepted will be able to continue its execution, in
particular it will be able to execute its "critical" section of code. When
this code has been executed, a call to <i>unlock</i> will unblock one of the
other threads that are waiting for the acceptance of their <i>lock</i>
operation.

<br>
<br> It should be clear by now why a binary semaphore is called a
<i>lower</i>-level synchronization concept. Apart from the fact that
a semaphore has no facilities for expressing additional synchronization
conditions, a binary semaphore is error-prone : the <i>lock</i> and
<i>unlock</i> invocations should always be carefully combined as
illustrated in the <a href="#worker">worker</a> object.

<pre>
**/

:-object semaphore1.

	lock.
	unlock.

	semaphore1 :-
		repeat,
			accept(lock),
			accept(unlock),
		fail.

:-end_object semaphore1.

/**
</pre>
Object <i>semaphore2</i> introduces the notion of state : non-logical
variable "<i>n</i>" denotes whether a lock has already been acquired
by a particular thread. The guards "<i>[ n > 0 ]</i>" and
"<i>[ n >= 0 ]</i>" provide for the conditions under which the
methods <i>lock</i> and <i>unlock</i> will be accepted.
<pre>
**/

:-object semaphore2.

	var n = 1.

	lock :-  -- n .
	unlock :- ++ n .

	semaphore2 :-
		repeat,
			accept(
				lock <== [ n > 0 ],
				unlock <== [ n >= 0 ]
			),
		fail.

:-end_object semaphore2.

/**
</pre>
Object <i>semaphore3</i> extends <i>semaphore2</i> : the actual code
of the <i>lock</i> and <i>unlock</i> operations is moved to the
<i>MethodBody</i> part of the corresponding <i>AcceptExpression</i>s.
<pre>
**/

:-object semaphore3.

	var n = 1.

	semaphore3 :-
		repeat,
			accept(
				lock <== [ n > 0 ] ==> -- n,
				unlock <== [ n >= 0 ] ==> ++ n
			),
		fail.

:-end_object semaphore3.

/**
</pre>
<a name="critical">
Object <i>critical</i> ...
<pre>
**/

:-object critical.

	var counter = 0.

	work(ThisWorker, Msecs) :-
		++ counter,
		format('~w~t: counter = ~w (block ~w msecs)~n', [ThisWorker, counter, Msecs]),
		sleep(Msecs).

:-end_object critical.


/***
</pre>
<a name="worker">
Object <i>worker</i> ...
<pre>
***/

:-object worker.

	var todo = 0.

	worker(ToDo, Sema, Msecs) :-
		todo := ToDo,
		loop(Sema, Msecs),
		format('end of ~w~n', [this]).

	loop(Sema, Msecs) :-
		repeat,
			Sema <- lock,
			critical <- work(this, Msecs),
			Sema <- unlock,
			-- todo,
		todo < 1,
		!.

:-end_object worker.

/**
</pre>

Remove the <i>text_area / 1</i> and <i>set_output / 1</i> calls below in
case you would like to run the example as a stand-alone program, i.e.
not as an applet in a browser. Note that the text in this html file is
actually comment in a DLP program : save it in e.g. pxsema.pl and
<a href="../docs/readme.html#compilation"> compile </a> /
<a href="../docs/readme.html#execution"> execute </a> the program.

<pre>
**/

:-object pxsema.

	main :-
		text_area(BrowserStream),	%% only required for execution
		set_output(BrowserStream),	%% in a browser

		%% PV := new(semaphore1),
		%% PV := new(semaphore2),
		PV := new(semaphore3),
		_W0 := new(worker(5, PV, 800)),
		_W1 := new(worker(5, PV, 400)),
		_W2 := new(worker(5, PV, 200)),
		format('end of ~w~n', [this]).

:-end_object pxsema.

/**
</pre>
</body>
</html>
**/
