Rendezvous: Difference between revisions
Content added Content deleted
m (Fixed lang tags.) |
(Added Oz.) |
||
Line 221: | Line 221: | ||
Return -1 |
Return -1 |
||
}</lang> |
}</lang> |
||
=={{header|Oz}}== |
|||
Oz does not have a rendezvous mechanism, but the task description lends itself to synchronous [http://c2.com/cgi/wiki?ActiveObject active objects]. We show how to implement this in Oz and then discuss the differences to the rendezvous model. |
|||
First a simple printer class whose definition is completely orthogonal to multithreading issues: |
|||
<lang oz>declare |
|||
class Printer |
|||
attr ink:5 |
|||
feat id backup |
|||
meth init(id:ID backup:Backup<=unit) |
|||
self.id = ID |
|||
self.backup = Backup |
|||
end |
|||
meth print(Line)=Msg |
|||
if @ink == 0 then |
|||
if self.backup == unit then |
|||
raise outOfInk end |
|||
else |
|||
{self.backup Msg} |
|||
end |
|||
else |
|||
{System.printInfo self.id#": "} |
|||
for C in Line do |
|||
{System.printInfo [C]} |
|||
end |
|||
{System.printInfo "\n"} |
|||
ink := @ink - 1 |
|||
end |
|||
end |
|||
end</lang> |
|||
Note how requeuing the task simply becomes delegation to a different object. |
|||
Active object are not a predefined abstraction in Oz. But due to Oz' first-class object messages, we can easily define it using ports and streams (many-to-one message passing): |
|||
<lang oz> fun {NewActiveSync Class Init} |
|||
Obj = {New Class Init} |
|||
MsgPort |
|||
in |
|||
thread MsgStream in |
|||
{NewPort ?MsgStream ?MsgPort} |
|||
for Msg#Sync in MsgStream do |
|||
try |
|||
{Obj Msg} |
|||
Sync = unit |
|||
catch E then |
|||
Sync = {Value.failed E} |
|||
end |
|||
end |
|||
end |
|||
proc {$ Msg} |
|||
Sync = {Port.sendRecv MsgPort Msg} |
|||
in |
|||
{Wait Sync} |
|||
end |
|||
end</lang> |
|||
This functions takes a class and an initialization message and returns a procedure. When called, this procedure will send messages to the new object in a new thread and then wait for the <code>Sync</code> variable to become bound. Exceptions are propagated using [http://www.mozart-oz.org/home/doc/base/node13.html#label696 failed values]. |
|||
This works because a unary procedure is syntactically indistinguishable from an object in Oz. |
|||
With this new abstraction we can create the two printers and execute both print tasks in their own thread: |
|||
<lang oz> Main = {NewActiveSync Printer init(id:1 backup:Reserve)} |
|||
Reserve = {NewActiveSync Printer init(id:2)} |
|||
in |
|||
%% task Humpty Dumpty |
|||
thread |
|||
try |
|||
{Main print("Humpty Dumpty sat on a wall.")} |
|||
{Main print("Humpty Dumpty had a great fall.")} |
|||
{Main print("All the king's horses and all the king's men")} |
|||
{Main print("Couldn't put Humpty together again.")} |
|||
catch outOfInk then |
|||
{System.showInfo " Humpty Dumpty out of ink!"} |
|||
end |
|||
end |
|||
%% task Mother Goose |
|||
thread |
|||
try |
|||
{Main print("Old Mother Goose")} |
|||
{Main print("When she wanted to wander,")} |
|||
{Main print("Would ride through the air")} |
|||
{Main print("On a very fine gander.")} |
|||
{Main print("Jack's mother came in,")} |
|||
{Main print("And caught the goose soon,")} |
|||
{Main print("And mounting its back,")} |
|||
{Main print("Flew up to the moon.")} |
|||
catch outOfInk then |
|||
{System.showInfo " Mother Goose out of ink!"} |
|||
end |
|||
end</lang> |
|||
Example output: |
|||
<pre> |
|||
1: Humpty Dumpty sat on a wall. |
|||
1: Old Mother Goose |
|||
1: Humpty Dumpty had a great fall. |
|||
1: When she wanted to wander, |
|||
1: All the king's horses and all the king's men |
|||
2: Would ride through the air |
|||
2: Couldn't put Humpty together again. |
|||
2: On a very fine gander. |
|||
2: Jack's mother came in, |
|||
2: And caught the goose soon, |
|||
Mother Goose out of ink! |
|||
</pre> |
|||
'''Comparison to Ada''' |
|||
What is called an "entry point" in Ada, is a method in our implementation. |
|||
We cannot limit the waiting time. This could be implemented in the NewActiveSync function, but it is not needed in the example task. |
|||
The callee task accepts rendezvous requests to the same entry point from multiple caller tasks. Similarly, the active object in Oz is designed to accept messages from different threads. To implement "rendezvous to different entry points", we simply add public methods to the Printer class. |
|||
The callee in ADA accepts one rendezvous at a time. The active object in Oz reads one message at a time from the stream. |
|||
Messages cannot be requeued in the given implementation. But we can delegate to a different active object which has the same effect, at least for the example given. |
|||
Like in the rendezvous mechanism, parameters are not marshalled. This is because sharing immutable data between threads is safe. |
|||
In contrast to ADA, the parameters are buffered until the printer becomes ready. But with a synchronous communication mechanism, this should not cause problems. |
|||
=={{header|Tcl}}== |
=={{header|Tcl}}== |