Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
7
Task/Rendezvous/00-META.yaml
Normal file
7
Task/Rendezvous/00-META.yaml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
category:
|
||||
- Encyclopedia
|
||||
from: http://rosettacode.org/wiki/Rendezvous
|
||||
note: Concurrency
|
||||
requires:
|
||||
- Concurrency
|
||||
30
Task/Rendezvous/00-TASK.txt
Normal file
30
Task/Rendezvous/00-TASK.txt
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
Demonstrate the “rendezvous” communications technique by implementing a printer monitor.
|
||||
==Detailed Description of Programming Task==
|
||||
Rendezvous is a synchronization mechanism based on procedural decomposition. Rendezvous is similar to a procedure call with the difference that the caller and the callee belong to different [[task]]s. The called procedure is usually called an '''entry point''' of the corresponding task. A call to an entry point is synchronous, i.e. the caller is blocked until completion. For the caller a call to the entry point is indivisible. Internally it consists of:
|
||||
|
||||
* Waiting for the callee ready to accept the rendezvous;
|
||||
* Engaging the rendezvous (servicing the entry point).
|
||||
|
||||
The caller may limit the waiting time to the callee to accept the rendezvous. I.e. a rendezvous request can be aborted if not yet accepted by the callee. When accepted the rendezvous is processed until its completion. During this time the caller and the callee tasks stay synchronized. Which context is used to process the rendezvous depends on the implementation which may wish to minimize context switching.
|
||||
|
||||
The callee task may accept several rendezvous requests:
|
||||
|
||||
* Rendezvous to the same entry point from different tasks;
|
||||
* Rendezvous to different entry points.
|
||||
|
||||
The callee accepts one rendezvous at a time.
|
||||
|
||||
Language mechanism of [[exceptions]] (if any) has to be consistent with the rendezvous. In particular when an exception is propagated out of a rendezvous it shall do in both tasks. The exception propagation is synchronous within the rendezvous and asynchronous outside it.
|
||||
|
||||
An engaged rendezvous can be requeued by the callee to another entry point of its task or to another task, transparently to the caller.
|
||||
|
||||
Differently to messages which are usually asynchronous, rendezvous are synchronous, as it was stated before. Therefore a rendezvous does not require marshaling the parameters and a buffer to keep them. Further, rendezvous can be implemented without context switch. This makes rendezvous a more efficient than messaging.
|
||||
|
||||
Rendezvous can be used to implement monitor synchronization objects. A monitor guards a shared resource. All users of the resource request a rendezvous to the monitor in order to get access to the resource. Access is granted by accepting the rendezvous for the time while the rendezvous is serviced.
|
||||
|
||||
===Language task===
|
||||
Show how rendezvous are supported by the language. If the language does not have rendezvous, provide an implementation of them based on other primitives.
|
||||
|
||||
===Use case task===
|
||||
Implement a printer monitor. The monitor guards a printer. There are two printers ''main'' and ''reserve''. Each has a monitor that accepts a rendezvous Print with a text line to print of the printer. The standard output may serve for printing purpose. Each character of the line is printed separately in order to illustrate that lines are printed indivisibly. Each printer has ink for only 5 lines of text. When the ''main'' printer runs out of ink it redirects its requests to the ''reserve'' printer. When that runs out of ink too, Out_Of_Ink exception propagates back to the caller. Create two writer tasks which print their plagiarisms on the printer. One does ''Humpty Dumpty'', another ''Mother Goose''.
|
||||
|
||||
6
Task/Rendezvous/Ada/rendezvous-1.ada
Normal file
6
Task/Rendezvous/Ada/rendezvous-1.ada
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
select
|
||||
Server.Wake_Up (Parameters);
|
||||
or delay 5.0;
|
||||
-- No response, try something else
|
||||
...
|
||||
end select;
|
||||
8
Task/Rendezvous/Ada/rendezvous-2.ada
Normal file
8
Task/Rendezvous/Ada/rendezvous-2.ada
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
select
|
||||
accept Wake_Up (Parameters : Work_Item) do
|
||||
Current_Work_Item := Parameters;
|
||||
end;
|
||||
Process (Current_Work_Item);
|
||||
or accept Shut_Down;
|
||||
exit; -- Shut down requested
|
||||
end select;
|
||||
77
Task/Rendezvous/Ada/rendezvous-3.ada
Normal file
77
Task/Rendezvous/Ada/rendezvous-3.ada
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
with Ada.Text_IO; use Ada.Text_IO;
|
||||
|
||||
procedure Rendezvous is
|
||||
Out_Of_Ink : exception;
|
||||
|
||||
type Printer;
|
||||
type Printer_Ptr is access all Printer;
|
||||
task type Printer (ID : Natural; Backup : Printer_Ptr) is
|
||||
entry Print (Line : String);
|
||||
end Printer;
|
||||
|
||||
task body Printer is
|
||||
Ink : Natural := 5;
|
||||
begin
|
||||
loop
|
||||
begin
|
||||
select
|
||||
accept Print (Line : String) do
|
||||
if Ink = 0 then
|
||||
if Backup = null then
|
||||
raise Out_Of_Ink;
|
||||
else
|
||||
requeue Backup.Print with abort;
|
||||
end if;
|
||||
else
|
||||
Put (Integer'Image (ID) & ": ");
|
||||
for I in Line'Range loop
|
||||
Put (Line (I));
|
||||
end loop;
|
||||
New_Line;
|
||||
Ink := Ink - 1;
|
||||
end if;
|
||||
end Print;
|
||||
or terminate;
|
||||
end select;
|
||||
exception
|
||||
when Out_Of_Ink =>
|
||||
null;
|
||||
end;
|
||||
end loop;
|
||||
end Printer;
|
||||
|
||||
Reserve : aliased Printer (2, null);
|
||||
Main : Printer (1, Reserve'Access);
|
||||
|
||||
task Humpty_Dumpty;
|
||||
task Mother_Goose;
|
||||
|
||||
task body Humpty_Dumpty is
|
||||
begin
|
||||
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.");
|
||||
exception
|
||||
when Out_Of_Ink =>
|
||||
Put_Line (" Humpty Dumpty out of ink!");
|
||||
end Humpty_Dumpty;
|
||||
|
||||
task body Mother_Goose is
|
||||
begin
|
||||
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.");
|
||||
exception
|
||||
when Out_Of_Ink =>
|
||||
Put_Line (" Mother Goose out of ink!");
|
||||
end Mother_Goose;
|
||||
|
||||
begin
|
||||
null;
|
||||
end Rendezvous;
|
||||
77
Task/Rendezvous/AutoHotkey/rendezvous.ahk
Normal file
77
Task/Rendezvous/AutoHotkey/rendezvous.ahk
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
OnMessage(0x4a, "PrintMonitor")
|
||||
SetTimer, print2, 400
|
||||
|
||||
print1:
|
||||
print("Old Mother Goose")
|
||||
print("When she wanted to wander,")
|
||||
print("Would ride through the air")
|
||||
print("On a very fine gander.")
|
||||
print("Jack's mother came in,")
|
||||
print("And caught the goose soon,")
|
||||
print("And mounting its back,")
|
||||
print("Flew up to the moon.")
|
||||
Return
|
||||
|
||||
print2:
|
||||
SetTimer, print2, Off
|
||||
print("Humpty Dumpty sat on a wall.")
|
||||
print("Humpty Dumpty had a great fall.")
|
||||
print("All the king's horses and all the king's men")
|
||||
print("Couldn't put Humpty together again.")
|
||||
Return
|
||||
|
||||
print(message)
|
||||
{
|
||||
Static StringToSend
|
||||
StringToSend := message
|
||||
Gui +LastFound
|
||||
VarSetCapacity(CopyDataStruct, 12, 0)
|
||||
NumPut(StrLen(StringToSend) + 1, CopyDataStruct, 4)
|
||||
NumPut(&StringToSend, CopyDataStruct, 8)
|
||||
SendMessage, 0x4a, 0, &CopyDataStruct
|
||||
If ErrorLevel
|
||||
MsgBox out of ink
|
||||
Sleep, 200
|
||||
Return
|
||||
}
|
||||
|
||||
PrintMonitor(wParam, lParam, msg)
|
||||
{
|
||||
Static ink = 5
|
||||
Global printed
|
||||
Critical
|
||||
If ink
|
||||
{
|
||||
StringAddress := NumGet(lParam + 8)
|
||||
StringLength := DllCall("lstrlen", UInt, StringAddress)
|
||||
VarSetCapacity(CopyOfData, StringLength)
|
||||
DllCall("lstrcpy", "str", CopyOfData, "uint", StringAddress)
|
||||
printed .= "primaryprinter: " . CopyOfData . "`n"
|
||||
ToolTip, primary printer`n: %printed%
|
||||
ink--
|
||||
}
|
||||
Else
|
||||
{
|
||||
OnMessage(0x4a, "Reserve")
|
||||
print(CopyOfData)
|
||||
}
|
||||
}
|
||||
|
||||
Reserve(wParam, lParam, msg)
|
||||
{
|
||||
Static ink = 5
|
||||
Global printed
|
||||
Critical
|
||||
If ink
|
||||
{
|
||||
StringAddress := NumGet(lParam + 8)
|
||||
StringLength := DllCall("lstrlen", UInt, StringAddress)
|
||||
VarSetCapacity(CopyOfData, StringLength)
|
||||
DllCall("lstrcpy", "str", CopyOfData, "uint", StringAddress)
|
||||
printed .= "reserveprinter: " . CopyOfData . "`n"
|
||||
ToolTip, Reserve printer`n: %printed%
|
||||
ink--
|
||||
}
|
||||
Else
|
||||
Return -1
|
||||
}
|
||||
230
Task/Rendezvous/C/rendezvous-1.c
Normal file
230
Task/Rendezvous/C/rendezvous-1.c
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/* The language task, implemented with pthreads for POSIX systems. */
|
||||
|
||||
/* Each rendezvous_t will be accepted by a single thread, and entered
|
||||
* by one or more threads. accept_func() only returns an integer and
|
||||
* is always run within the entering thread's context to simplify
|
||||
* handling the arguments and return value. This somewhat unlike an
|
||||
* Ada rendezvous and is a subset of the Ada rendezvous functionality.
|
||||
* Ada's in and out parameters can be simulated via the void pointer
|
||||
* passed to accept_func() to update variables owned by both the
|
||||
* entering and accepting threads, if a suitable struct with pointers
|
||||
* to those variables is used. */
|
||||
typedef struct rendezvous {
|
||||
pthread_mutex_t lock; /* A mutex/lock to use with the CVs. */
|
||||
pthread_cond_t cv_entering; /* Signaled when a thread enters. */
|
||||
pthread_cond_t cv_accepting; /* Signaled when accepting thread is ready. */
|
||||
pthread_cond_t cv_done; /* Signaled when accept_func() finishes. */
|
||||
int (*accept_func)(void*); /* The function to run when accepted. */
|
||||
int entering; /* Number of threads trying to enter. */
|
||||
int accepting; /* True if the accepting thread is ready. */
|
||||
int done; /* True if accept_func() is done. */
|
||||
} rendezvous_t;
|
||||
|
||||
/* Static initialization for rendezvous_t. */
|
||||
#define RENDEZVOUS_INITILIZER(accept_function) { \
|
||||
.lock = PTHREAD_MUTEX_INITIALIZER, \
|
||||
.cv_entering = PTHREAD_COND_INITIALIZER, \
|
||||
.cv_accepting = PTHREAD_COND_INITIALIZER, \
|
||||
.cv_done = PTHREAD_COND_INITIALIZER, \
|
||||
.accept_func = accept_function, \
|
||||
.entering = 0, \
|
||||
.accepting = 0, \
|
||||
.done = 0, \
|
||||
}
|
||||
|
||||
int enter_rendezvous(rendezvous_t *rv, void* data)
|
||||
{
|
||||
/* Arguments are passed in and out of the rendezvous via
|
||||
* (void*)data, and the accept_func() return value is copied and
|
||||
* returned to the caller (entering thread). A data struct with
|
||||
* pointers to variables in both the entering and accepting
|
||||
* threads can be used to simulate Ada's in and out parameters, if
|
||||
* needed. */
|
||||
pthread_mutex_lock(&rv->lock);
|
||||
|
||||
rv->entering++;
|
||||
pthread_cond_signal(&rv->cv_entering);
|
||||
|
||||
while (!rv->accepting) {
|
||||
/* Nothing is accepting yet, keep waiting. pthreads will
|
||||
* queue all waiting entries. The loop is needed to handle
|
||||
* both race conditions and spurious wakeups. */
|
||||
pthread_cond_wait(&rv->cv_accepting, &rv->lock);
|
||||
}
|
||||
|
||||
/* Call accept_func() and copy the return value before leaving
|
||||
* the mutex. */
|
||||
int ret = rv->accept_func(data);
|
||||
|
||||
/* This signal is needed so that the accepting thread will wait
|
||||
* for the rendezvous to finish before trying to accept again. */
|
||||
rv->done = 1;
|
||||
pthread_cond_signal(&rv->cv_done);
|
||||
|
||||
rv->entering--;
|
||||
rv->accepting = 0;
|
||||
pthread_mutex_unlock(&rv->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void accept_rendezvous(rendezvous_t *rv)
|
||||
{
|
||||
/* This accept function does not take in or return parameters.
|
||||
* That is handled on the entry side. This is only for
|
||||
* synchronization. */
|
||||
pthread_mutex_lock(&rv->lock);
|
||||
rv->accepting = 1;
|
||||
|
||||
while (!rv->entering) {
|
||||
/* Nothing to accept yet, keep waiting. */
|
||||
pthread_cond_wait(&rv->cv_entering, &rv->lock);
|
||||
}
|
||||
|
||||
pthread_cond_signal(&rv->cv_accepting);
|
||||
|
||||
while (!rv->done) {
|
||||
/* Wait for accept_func() to finish. */
|
||||
pthread_cond_wait(&rv->cv_done, &rv->lock);
|
||||
}
|
||||
rv->done = 0;
|
||||
|
||||
rv->accepting = 0;
|
||||
pthread_mutex_unlock(&rv->lock);
|
||||
}
|
||||
|
||||
/* The printer use case task implemented using the above rendezvous
|
||||
* implementation. Since C doesn't have exceptions, return values are
|
||||
* used to signal out of ink errors. */
|
||||
|
||||
typedef struct printer {
|
||||
rendezvous_t rv;
|
||||
struct printer *backup;
|
||||
int id;
|
||||
int remaining_lines;
|
||||
} printer_t;
|
||||
|
||||
typedef struct print_args {
|
||||
struct printer *printer;
|
||||
const char* line;
|
||||
} print_args_t;
|
||||
|
||||
int print_line(printer_t *printer, const char* line) {
|
||||
print_args_t args;
|
||||
args.printer = printer;
|
||||
args.line = line;
|
||||
return enter_rendezvous(&printer->rv, &args);
|
||||
}
|
||||
|
||||
int accept_print(void* data) {
|
||||
/* This is called within the rendezvous, so everything is locked
|
||||
* and okay to modify. */
|
||||
print_args_t *args = (print_args_t*)data;
|
||||
printer_t *printer = args->printer;
|
||||
const char* line = args->line;
|
||||
|
||||
if (printer->remaining_lines) {
|
||||
/* Print the line, character by character. */
|
||||
printf("%d: ", printer->id);
|
||||
while (*line != '\0') {
|
||||
putchar(*line++);
|
||||
}
|
||||
putchar('\n');
|
||||
printer->remaining_lines--;
|
||||
return 1;
|
||||
}
|
||||
else if (printer->backup) {
|
||||
/* "Requeue" this rendezvous with the backup printer. */
|
||||
return print_line(printer->backup, line);
|
||||
}
|
||||
else {
|
||||
/* Out of ink, and no backup available. */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
printer_t backup_printer = {
|
||||
.rv = RENDEZVOUS_INITILIZER(accept_print),
|
||||
.backup = NULL,
|
||||
.id = 2,
|
||||
.remaining_lines = 5,
|
||||
};
|
||||
|
||||
printer_t main_printer = {
|
||||
.rv = RENDEZVOUS_INITILIZER(accept_print),
|
||||
.backup = &backup_printer,
|
||||
.id = 1,
|
||||
.remaining_lines = 5,
|
||||
};
|
||||
|
||||
void* printer_thread(void* thread_data) {
|
||||
printer_t *printer = (printer_t*) thread_data;
|
||||
while (1) {
|
||||
accept_rendezvous(&printer->rv);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct poem {
|
||||
char* name;
|
||||
char* lines[];
|
||||
} poem_t;
|
||||
|
||||
poem_t humpty_dumpty = {
|
||||
.name = "Humpty Dumpty",
|
||||
.lines = {
|
||||
"Humpty Dumpty sat on a wall.",
|
||||
"Humpty Dumpty had a great fall.",
|
||||
"All the king's horses and all the king's men",
|
||||
"Couldn't put Humpty together again.",
|
||||
""
|
||||
},
|
||||
};
|
||||
|
||||
poem_t mother_goose = {
|
||||
.name = "Mother Goose",
|
||||
.lines = {
|
||||
"Old Mother Goose",
|
||||
"When she wanted to wander,",
|
||||
"Would ride through the air",
|
||||
"On a very fine gander.",
|
||||
"Jack's mother came in,",
|
||||
"And caught the goose soon,",
|
||||
"And mounting its back,",
|
||||
"Flew up to the moon.",
|
||||
""
|
||||
},
|
||||
};
|
||||
|
||||
void* poem_thread(void* thread_data) {
|
||||
poem_t *poem = (poem_t*)thread_data;
|
||||
|
||||
for (unsigned i = 0; poem->lines[i] != ""; i++) {
|
||||
int ret = print_line(&main_printer, poem->lines[i]);
|
||||
if (ret < 0) {
|
||||
printf(" %s out of ink!\n", poem->name);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
pthread_t threads[4];
|
||||
|
||||
pthread_create(&threads[0], NULL, poem_thread, &humpty_dumpty);
|
||||
pthread_create(&threads[1], NULL, poem_thread, &mother_goose);
|
||||
pthread_create(&threads[2], NULL, printer_thread, &main_printer);
|
||||
pthread_create(&threads[3], NULL, printer_thread, &backup_printer);
|
||||
|
||||
pthread_join(threads[0], NULL);
|
||||
pthread_join(threads[1], NULL);
|
||||
pthread_cancel(threads[2]);
|
||||
pthread_cancel(threads[3]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
72
Task/Rendezvous/C/rendezvous-2.c
Normal file
72
Task/Rendezvous/C/rendezvous-2.c
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <omp.h>
|
||||
|
||||
typedef struct printer printer;
|
||||
struct printer { int id, ink; };
|
||||
printer pnt_main = { 1, 5 };
|
||||
printer pnt_backup = { 2, 5 };
|
||||
|
||||
int print(const char * text, const char **error)
|
||||
{
|
||||
#pragma omp critical
|
||||
{
|
||||
printer *p = &pnt_main;
|
||||
if (!p->ink) p = &pnt_backup;
|
||||
if (!p->ink)
|
||||
*error = "Out of ink";
|
||||
else {
|
||||
*error = 0;
|
||||
p->ink--;
|
||||
printf("%d | ", p->id, p->ink);
|
||||
while (*text != '\0') {
|
||||
putchar(*(text++));
|
||||
fflush(stdout);
|
||||
usleep(30000);
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
return 0 != *error;
|
||||
}
|
||||
|
||||
const char *humpty[] = {
|
||||
"Humpty Dumpty sat on a wall.",
|
||||
"Humpty Dumpty had a great fall.",
|
||||
"All the king's horses and all the king's men,",
|
||||
"Couldn't put Humpty together again."
|
||||
};
|
||||
|
||||
const char *goose[] = {
|
||||
"Old Mother Goose,",
|
||||
"When she wanted to wander,",
|
||||
"Would ride through the air,",
|
||||
"On a very fine gander.",
|
||||
"Jack's mother came in,",
|
||||
"And caught the goose soon,",
|
||||
"And mounting its back,",
|
||||
"Flew up to the moon."
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
int i, j, len;
|
||||
const char *msg, **text;
|
||||
|
||||
omp_set_num_threads(2);
|
||||
|
||||
#pragma omp parallel for private(text, msg, len, j)
|
||||
for (i = 0; i < 2; i++) {
|
||||
text = i ? goose : humpty;
|
||||
len = (i ? sizeof(goose) : sizeof(humpty) ) / sizeof(const char*);
|
||||
for (j = 0; j < len; j++) {
|
||||
usleep(100000);
|
||||
if (print(text[j], &msg)) {
|
||||
fprintf(stderr, "Error: %s\n", msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
105
Task/Rendezvous/D/rendezvous.d
Normal file
105
Task/Rendezvous/D/rendezvous.d
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
import std.stdio, std.array, std.datetime, std.exception,
|
||||
std.concurrency, core.thread, core.atomic;
|
||||
|
||||
final class OutOfInk: Exception {
|
||||
this() pure nothrow {
|
||||
super("Out of ink.");
|
||||
}
|
||||
}
|
||||
|
||||
struct Printer {
|
||||
string id;
|
||||
size_t ink;
|
||||
|
||||
void printIt(in string line) {
|
||||
enforce(ink != 0, new OutOfInk);
|
||||
writefln("%s: %s", id, line);
|
||||
ink--;
|
||||
}
|
||||
}
|
||||
|
||||
/// Treats shared lvalue as if it is thread-local.
|
||||
ref assumeThreadLocal(T)(ref shared T what) pure nothrow {
|
||||
return *cast(T*)&what;
|
||||
}
|
||||
|
||||
struct RendezvousPrinter {
|
||||
Printer[] printers;
|
||||
|
||||
void print(const(string)[] lines) shared {
|
||||
OutOfInk savedException;
|
||||
|
||||
// Lightweight mutual exclusion
|
||||
// using shared atomic bool.
|
||||
shared static bool mutex;
|
||||
|
||||
void lock() {
|
||||
while (!cas(&mutex, false, true))
|
||||
Thread.sleep(1.hnsecs);
|
||||
}
|
||||
|
||||
void unlock() nothrow {
|
||||
assert(mutex.atomicLoad!(MemoryOrder.acq));
|
||||
mutex.atomicStore!(MemoryOrder.rel)(false);
|
||||
}
|
||||
|
||||
while (!lines.empty) {
|
||||
if (printers.empty) {
|
||||
// No more printers to try.
|
||||
assert(savedException !is null);
|
||||
throw savedException;
|
||||
}
|
||||
|
||||
try {
|
||||
{
|
||||
lock;
|
||||
scope(exit) unlock;
|
||||
printers.front.assumeThreadLocal
|
||||
.printIt(lines.front);
|
||||
}
|
||||
lines.popFront;
|
||||
|
||||
// Increase the chance of interleaved output.
|
||||
Thread.sleep(10.msecs);
|
||||
} catch (OutOfInk exc) {
|
||||
savedException = exc;
|
||||
|
||||
// Switch to the next printer.
|
||||
lock;
|
||||
scope(exit) unlock;
|
||||
printers.assumeThreadLocal.popFront;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void humptyDumptyTask(shared ref RendezvousPrinter rendezvous) {
|
||||
const humptyDumpty = [
|
||||
"Humpty Dumpty sat on a wall.",
|
||||
"Humpty Dumpty had a great fall.",
|
||||
"All the king's horses and all the king's men,",
|
||||
"Couldn't put Humpty together again."];
|
||||
|
||||
rendezvous.print(humptyDumpty);
|
||||
}
|
||||
|
||||
void motherGooseTask(shared ref RendezvousPrinter rendezvous) {
|
||||
const motherGoose = ["Old Mother Goose,",
|
||||
"When she wanted to wander,",
|
||||
"Would ride through the air,",
|
||||
"On a very fine gander.",
|
||||
"Jack's mother came in,",
|
||||
"And caught the goose soon,",
|
||||
"And mounting its back,",
|
||||
"Flew up to the moon."];
|
||||
|
||||
rendezvous.print(motherGoose);
|
||||
}
|
||||
|
||||
void main() {
|
||||
shared rendezvous = RendezvousPrinter
|
||||
([Printer("main", 5), Printer("reserve", 5)]);
|
||||
|
||||
spawn(&humptyDumptyTask, rendezvous);
|
||||
spawn(&motherGooseTask, rendezvous);
|
||||
}
|
||||
86
Task/Rendezvous/Erlang/rendezvous.erl
Normal file
86
Task/Rendezvous/Erlang/rendezvous.erl
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
-module( rendezvous ).
|
||||
|
||||
-export( [task/0] ).
|
||||
|
||||
task() ->
|
||||
Printer_pid = erlang:spawn( fun() -> printer(1, 5) end ),
|
||||
Reserve_printer_pid = erlang:spawn( fun() -> printer(2, 5) end ),
|
||||
Monitor_pid = erlang:spawn( fun() -> printer_monitor(Printer_pid, Reserve_printer_pid) end ),
|
||||
erlang:spawn( fun() -> print(Monitor_pid, humpty_dumpty()) end ),
|
||||
erlang:spawn( fun() -> print(Monitor_pid, mother_goose()) end ).
|
||||
|
||||
humpty_dumpty() ->
|
||||
["Humpty Dumpty sat on a wall.",
|
||||
"Humpty Dumpty had a great fall.",
|
||||
"All the king's horses and all the king's men,",
|
||||
"Couldn't put Humpty together again."].
|
||||
|
||||
mother_goose() ->
|
||||
["Old Mother Goose,",
|
||||
"When she wanted to wander,",
|
||||
"Would ride through the air,",
|
||||
"On a very fine gander.",
|
||||
"Jack's mother came in,",
|
||||
"And caught the goose soon,",
|
||||
"And mounting its back,",
|
||||
"Flew up to the moon."].
|
||||
|
||||
print( Pid, Lines ) ->
|
||||
io:fwrite( "Print ~p started~n", [erlang:self()] ),
|
||||
print( Pid, Lines, infinity ).
|
||||
|
||||
print( _Pid, [], _Timeout ) -> ok;
|
||||
print( Pid, [Line | T], Timeout ) ->
|
||||
print_line( Pid, Line, Timeout ),
|
||||
print_line_done(),
|
||||
print( Pid, T, Timeout ).
|
||||
|
||||
print_line( Pid, Line, Timeout ) ->
|
||||
Pid ! {print, Line, erlang:self()},
|
||||
receive
|
||||
{print, started} -> ok
|
||||
after Timeout -> erlang:throw( timeout )
|
||||
end.
|
||||
|
||||
print_line_done() ->
|
||||
receive
|
||||
{printer, ok} -> ok;
|
||||
{printer, out_of_ink} -> erlang:throw( out_of_ink )
|
||||
end.
|
||||
|
||||
printer( N, 0 ) ->
|
||||
receive
|
||||
{print, _Line, Pid} -> Pid ! {printer, out_of_ink}
|
||||
end,
|
||||
printer( N, 0 );
|
||||
printer( N, Ink ) ->
|
||||
receive
|
||||
{print, Line, Pid} ->
|
||||
Pid ! {printer, ok},
|
||||
io:fwrite( "~p: ", [N] ),
|
||||
[io:fwrite("~c", [X]) || X <- Line],
|
||||
io:nl()
|
||||
end,
|
||||
printer( N, Ink - 1 ).
|
||||
|
||||
printer_monitor( Printer, Reserve ) ->
|
||||
{Line, Pid} = printer_monitor_get_line(),
|
||||
Result = printer_monitor_print_line( Printer, Line ),
|
||||
printer_monitor_reserve( Result, Reserve, Line, Pid ),
|
||||
printer_monitor( Printer, Reserve ).
|
||||
|
||||
printer_monitor_get_line() ->
|
||||
receive
|
||||
{print, Line, Pid} ->
|
||||
Pid ! {print, started},
|
||||
{Line, Pid}
|
||||
end.
|
||||
|
||||
printer_monitor_print_line( Printer_pid, Line ) ->
|
||||
Printer_pid ! {print, Line, erlang:self()},
|
||||
receive
|
||||
{printer, Result} -> Result
|
||||
end.
|
||||
|
||||
printer_monitor_reserve( ok, _Reserve_pid, _Line, Pid ) -> Pid ! {printer, ok};
|
||||
printer_monitor_reserve( out_of_ink, Reserve_pid, Line, Pid ) -> Reserve_pid ! {print, Line, Pid}.
|
||||
76
Task/Rendezvous/F-Sharp/rendezvous.fs
Normal file
76
Task/Rendezvous/F-Sharp/rendezvous.fs
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
open System
|
||||
|
||||
type PrinterCommand = Print of string
|
||||
|
||||
// a message is a command and a facility to return an exception
|
||||
type Message = Message of PrinterCommand * AsyncReplyChannel<Exception option>
|
||||
|
||||
// thrown if we have no more ink (and neither has our possible backup printer)
|
||||
exception OutOfInk
|
||||
|
||||
type Printer(id, ?backup:Printer) =
|
||||
let mutable ink = 5
|
||||
|
||||
// the actual printing logic as a private function
|
||||
let print line =
|
||||
if ink > 0 then
|
||||
printf "%d: " id
|
||||
Seq.iter (printf "%c") line
|
||||
printf "\n"
|
||||
ink <- ink - 1
|
||||
else
|
||||
match backup with
|
||||
| Some p -> p.Print line
|
||||
| None -> raise OutOfInk
|
||||
|
||||
// use a MailboxProcessor to process commands asynchronously;
|
||||
// if an exception occurs, we return it to the calling thread
|
||||
let agent = MailboxProcessor.Start( fun inbox ->
|
||||
async {
|
||||
while true do
|
||||
let! Message (command, replyChannel) = inbox.Receive()
|
||||
try
|
||||
match command with
|
||||
| Print line -> print line
|
||||
replyChannel.Reply None
|
||||
with
|
||||
| ex -> replyChannel.Reply (Some ex)
|
||||
})
|
||||
|
||||
// public printing method:
|
||||
// send Print command and propagate exception if one occurs
|
||||
member x.Print line =
|
||||
match agent.PostAndReply( fun replyChannel -> Message (Print line, replyChannel) ) with
|
||||
| None -> ()
|
||||
| Some ex -> raise ex
|
||||
|
||||
|
||||
open System.Threading
|
||||
|
||||
do
|
||||
let main = new Printer(id=1, backup=new Printer(id=2))
|
||||
|
||||
(new Thread(fun () ->
|
||||
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."
|
||||
with
|
||||
| OutOfInk -> printfn " Humpty Dumpty out of ink!"
|
||||
)).Start()
|
||||
|
||||
(new Thread(fun () ->
|
||||
try
|
||||
main.Print "Old Mother Goose"
|
||||
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."
|
||||
with
|
||||
| OutOfInk -> printfn " Mother Goose out of ink!"
|
||||
)).Start()
|
||||
|
||||
Console.ReadLine() |> ignore
|
||||
145
Task/Rendezvous/Go/rendezvous.go
Normal file
145
Task/Rendezvous/Go/rendezvous.go
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var hdText = `Humpty Dumpty sat on a wall.
|
||||
Humpty Dumpty had a great fall.
|
||||
All the king's horses and all the king's men,
|
||||
Couldn't put Humpty together again.`
|
||||
|
||||
var mgText = `Old Mother Goose,
|
||||
When she wanted to wander,
|
||||
Would ride through the air,
|
||||
On a very fine gander.
|
||||
Jack's mother came in,
|
||||
And caught the goose soon,
|
||||
And mounting its back,
|
||||
Flew up to the moon.`
|
||||
|
||||
func main() {
|
||||
reservePrinter := startMonitor(newPrinter(5), nil)
|
||||
mainPrinter := startMonitor(newPrinter(5), reservePrinter)
|
||||
var busy sync.WaitGroup
|
||||
busy.Add(2)
|
||||
go writer(mainPrinter, "hd", hdText, &busy)
|
||||
go writer(mainPrinter, "mg", mgText, &busy)
|
||||
busy.Wait()
|
||||
}
|
||||
|
||||
// printer is a type representing an abstraction of a physical printer.
|
||||
// It is a type defintion for a function that takes a string to print
|
||||
// and returns an error value, (hopefully usually nil, meaning no error.)
|
||||
type printer func(string) error
|
||||
|
||||
// newPrinter is a constructor. The parameter is a quantity of ink. It
|
||||
// returns a printer object encapsulating the ink quantity.
|
||||
// Note that this is not creating the monitor, only the object serving as
|
||||
// a physical printer by writing to standard output.
|
||||
func newPrinter(ink int) printer {
|
||||
return func(line string) error {
|
||||
if ink == 0 {
|
||||
return eOutOfInk
|
||||
}
|
||||
for _, c := range line {
|
||||
fmt.Printf("%c", c)
|
||||
}
|
||||
fmt.Println()
|
||||
ink--
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var eOutOfInk = errors.New("out of ink")
|
||||
|
||||
// For the language task, rSync is a type used to approximate the Ada
|
||||
// rendezvous mechanism that includes the caller waiting for completion
|
||||
// of the callee. For this use case, we signal completion with an error
|
||||
// value as a response. Exceptions are not idiomatic in Go and there is
|
||||
// no attempt here to model the Ada exception mechanism. Instead, it is
|
||||
// idomatic in Go to return error values. Sending an error value on a
|
||||
// channel works well here to signal completion. Go unbuffered channels
|
||||
// provide synchronous rendezvous, but call and response takes two channels,
|
||||
// which are bundled together here in a struct. The channel types are chosen
|
||||
// to mirror the parameter and return types of "type printer" defined above.
|
||||
// The channel types here, string and error are both "reference types"
|
||||
// in Go terminology. That is, they are small things containing pointers
|
||||
// to the actual data. Sending one on a channel does not involve copying,
|
||||
// or much less marshalling string data.
|
||||
type rSync struct {
|
||||
call chan string
|
||||
response chan error
|
||||
}
|
||||
|
||||
// "rendezvous Print" requested by use case task.
|
||||
// For the language task though, it is implemented here as a method on
|
||||
// rSync that sends its argument on rSync.call and returns the result
|
||||
// received from rSync.response. Each channel operation is synchronous.
|
||||
// The two operations back to back approximate the Ada rendezvous.
|
||||
func (r *rSync) print(data string) error {
|
||||
r.call <- data // blocks until data is accepted on channel
|
||||
return <-r.response // blocks until response is received
|
||||
}
|
||||
|
||||
// monitor is run as a goroutine. It encapsulates the printer passed to it.
|
||||
// Print requests are received through the rSync object "entry," named entry
|
||||
// here to correspond to the Ada concept of an entry point.
|
||||
func monitor(hardPrint printer, entry, reserve *rSync) {
|
||||
for {
|
||||
// The monitor goroutine will block here waiting for a "call"
|
||||
// to its "entry point."
|
||||
data := <-entry.call
|
||||
// Assuming the call came from a goroutine calling rSync.print,
|
||||
// that goroutine is now blocked, waiting for this one to send
|
||||
// a response.
|
||||
|
||||
// attempt output
|
||||
switch err := hardPrint(data); {
|
||||
|
||||
// consider return value from attempt
|
||||
case err == nil:
|
||||
entry.response <- nil // no problems
|
||||
|
||||
case err == eOutOfInk && reserve != nil:
|
||||
// Requeue to "entry point" of reserve printer monitor.
|
||||
// Caller stays blocked, and now this goroutine blocks until
|
||||
// it gets a response from the reserve printer monitor.
|
||||
// It then transparently relays the response to the caller.
|
||||
entry.response <- reserve.print(data)
|
||||
|
||||
default:
|
||||
entry.response <- err // return failure
|
||||
}
|
||||
// The response is away. Loop, and so immediately block again.
|
||||
}
|
||||
}
|
||||
|
||||
// startMonitor can be seen as an rSync constructor. It also
|
||||
// of course, starts the monitor for which the rSync serves as entry point.
|
||||
// Further to the langauge task, note that the channels created here are
|
||||
// unbuffered. There is no buffer or message box to hold channel data.
|
||||
// A sender will block waiting for a receiver to accept data synchronously.
|
||||
func startMonitor(p printer, reservePrinter *rSync) *rSync {
|
||||
entry := &rSync{make(chan string), make(chan error)}
|
||||
go monitor(p, entry, reservePrinter)
|
||||
return entry
|
||||
}
|
||||
|
||||
// Two writer tasks are started as goroutines by main. They run concurrently
|
||||
// and compete for printers as resources. Note the call to "rendezvous Print"
|
||||
// as requested in the use case task and compare the syntax,
|
||||
// Here: printMonitor.print(line);
|
||||
// Ada solution: Main.Print ("string literal");
|
||||
func writer(printMonitor *rSync, id, text string, busy *sync.WaitGroup) {
|
||||
for _, line := range strings.Split(text, "\n") {
|
||||
if err := printMonitor.print(line); err != nil {
|
||||
fmt.Printf("**** writer task %q terminated: %v ****\n", id, err)
|
||||
break
|
||||
}
|
||||
}
|
||||
busy.Done()
|
||||
}
|
||||
74
Task/Rendezvous/Julia/rendezvous.julia
Normal file
74
Task/Rendezvous/Julia/rendezvous.julia
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
mutable struct Printer
|
||||
inputpath::Channel{String}
|
||||
errorpath::Channel{String}
|
||||
inkremaining::Int32
|
||||
reserve::Printer
|
||||
name::String
|
||||
function Printer(ch1, ch2, ink, name)
|
||||
this = new()
|
||||
this.inputpath = ch1
|
||||
this.errorpath = ch2
|
||||
this.inkremaining = ink
|
||||
this.name = name
|
||||
this.reserve = this
|
||||
this
|
||||
end
|
||||
end
|
||||
|
||||
function lineprintertask(printer)
|
||||
while true
|
||||
line = take!(printer.inputpath)
|
||||
linesprinted = 0
|
||||
if(printer.inkremaining < 1)
|
||||
if(printer.reserve == printer)
|
||||
put!(printer.errorpath, "Error: printer $(printer.name) out of ink")
|
||||
else
|
||||
put!(printer.reserve.inputpath, line)
|
||||
end
|
||||
else
|
||||
println(line)
|
||||
printer.inkremaining -= 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function schedulework(poems)
|
||||
printerclose(printer) = (close(printer.inputpath); close(printer.errorpath))
|
||||
reserveprinter = Printer(Channel{String}(1), Channel{String}(10), 5, "Reserve")
|
||||
mainprinter = Printer(Channel{String}(1), Channel{String}(10), 5, "Main")
|
||||
mainprinter.reserve = reserveprinter
|
||||
@async(lineprintertask(mainprinter))
|
||||
@async(lineprintertask(reserveprinter))
|
||||
printers = [mainprinter, reserveprinter]
|
||||
activeprinter = 1
|
||||
@sync(
|
||||
for poem in poems
|
||||
activeprinter = (activeprinter % length(printers)) + 1
|
||||
@async(
|
||||
for line in poem
|
||||
put!(printers[activeprinter].inputpath, line)
|
||||
end)
|
||||
end)
|
||||
for p in printers
|
||||
while isready(p.errorpath)
|
||||
println(take!(p.errorpath))
|
||||
end
|
||||
printerclose(p)
|
||||
end
|
||||
end
|
||||
|
||||
const humptydumpty = ["Humpty Dumpty sat on a wall.",
|
||||
"Humpty Dumpty had a great fall.",
|
||||
"All the king's horses and all the king's men,",
|
||||
"Couldn't put Humpty together again."]
|
||||
|
||||
const oldmothergoose = ["Old Mother Goose,",
|
||||
"When she wanted to wander,",
|
||||
"Would ride through the air,",
|
||||
"On a very fine gander.",
|
||||
"Jack's mother came in,",
|
||||
"And caught the goose soon,",
|
||||
"And mounting its back,",
|
||||
"Flew up to the moon."]
|
||||
|
||||
schedulework([humptydumpty, oldmothergoose])
|
||||
53
Task/Rendezvous/Nim/rendezvous.nim
Normal file
53
Task/Rendezvous/Nim/rendezvous.nim
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import asyncdispatch, options, strutils
|
||||
type
|
||||
Printer = ref object
|
||||
inkLevel, id: int
|
||||
backup: Option[Printer]
|
||||
OutOfInkException = object of IOError
|
||||
proc print(p: Printer, line: string){.async.} =
|
||||
if p.inkLevel <= 0:
|
||||
if p.backup.isNone():
|
||||
raise newException(OutOfInkException, "out of ink")
|
||||
else:
|
||||
await p.backup.get().print(line)
|
||||
else:
|
||||
p.inkLevel-=1
|
||||
stdout.writeLine("$1:$2".format(p.id, line))
|
||||
await sleepAsync(100)
|
||||
proc newPrinter(inkLevel, id: int, backup: Option[Printer]): Printer =
|
||||
new(result)
|
||||
result.inkLevel = inkLevel
|
||||
result.id = id
|
||||
result.backup = backup
|
||||
|
||||
proc print(p: Printer, msg: seq[string]){.async.} =
|
||||
for line in msg:
|
||||
try:
|
||||
await p.print(line)
|
||||
except OutOfInkException as e:
|
||||
echo("out of ink")
|
||||
break
|
||||
const
|
||||
humptyLines = @[
|
||||
"Humpty Dumpty sat on a wall.",
|
||||
"Humpty Dumpty had a great fall.",
|
||||
"All the king's horses and all the king's men,",
|
||||
"Couldn't put Humpty together again.",
|
||||
]
|
||||
gooseLines = @[
|
||||
"Old Mother Goose,",
|
||||
"When she wanted to wander,",
|
||||
"Would ride through the air,",
|
||||
"On a very fine gander.",
|
||||
"Jack's mother came in,",
|
||||
"And caught the goose soon,",
|
||||
"And mounting its back,",
|
||||
"Flew up to the moon.",
|
||||
]
|
||||
proc main(){.async.} =
|
||||
var
|
||||
reservePrinter = newPrinter(5, 2, none(Printer))
|
||||
mainPrinter = newPrinter(5, 1, some(reservePrinter))
|
||||
await mainPrinter.print(gooseLines) and mainPrinter.print(humptyLines)
|
||||
|
||||
waitFor main()
|
||||
28
Task/Rendezvous/Oz/rendezvous-1.oz
Normal file
28
Task/Rendezvous/Oz/rendezvous-1.oz
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
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
|
||||
21
Task/Rendezvous/Oz/rendezvous-2.oz
Normal file
21
Task/Rendezvous/Oz/rendezvous-2.oz
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
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
|
||||
30
Task/Rendezvous/Oz/rendezvous-3.oz
Normal file
30
Task/Rendezvous/Oz/rendezvous-3.oz
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
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
|
||||
47
Task/Rendezvous/Phix/rendezvous.phix
Normal file
47
Task/Rendezvous/Phix/rendezvous.phix
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
(notonline)-->
|
||||
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (threads)</span>
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">print_cs</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">init_cs</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #008080;">enum</span> <span style="color: #000000;">NAME</span><span style="color: #0000FF;">,</span><span style="color: #000000;">INK</span>
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">printers</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #008000;">"main"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">},</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #008000;">"reserve"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">}}</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">printer</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">name</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">try</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #7060A8;">enter_cs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">print_cs</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">printers</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">printers</span><span style="color: #0000FF;">[</span><span style="color: #000000;">p</span><span style="color: #0000FF;">][</span><span style="color: #000000;">INK</span><span style="color: #0000FF;">]!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">printers</span><span style="color: #0000FF;">[</span><span style="color: #000000;">p</span><span style="color: #0000FF;">][</span><span style="color: #000000;">INK</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s/%s: %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">name</span><span style="color: #0000FF;">,</span><span style="color: #000000;">printers</span><span style="color: #0000FF;">[</span><span style="color: #000000;">p</span><span style="color: #0000FF;">][</span><span style="color: #000000;">NAME</span><span style="color: #0000FF;">],</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]})</span>
|
||||
<span style="color: #008080;">exit</span>
|
||||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">printers</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">throw</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"out of ink"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #7060A8;">leave_cs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">print_cs</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #7060A8;">exit_thread</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">catch</span> <span style="color: #000000;">e</span>
|
||||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"exception(%s): %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">name</span><span style="color: #0000FF;">,</span><span style="color: #000000;">e</span><span style="color: #0000FF;">[</span><span style="color: #004600;">E_USER</span><span style="color: #0000FF;">]})</span>
|
||||
<span style="color: #7060A8;">leave_cs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">print_cs</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">exit_thread</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">try</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">hd</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"Humpty Dumpty sat on a wall."</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #008000;">"Humpty Dumpty had a great fall."</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #008000;">"All the king's horses and all the king's men"</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #008000;">"Couldn't put Humpty together again."</span><span style="color: #0000FF;">},</span>
|
||||
<span style="color: #000000;">mg</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"Old Mother Goose"</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #008000;">"When she wanted to wander,"</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #008000;">"Would ride through the air"</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #008000;">"On a very fine gander."</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #008000;">"Jack's mother came in,"</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #008000;">"And caught the goose soon,"</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #008000;">"And mounting its back,"</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #008000;">"Flew up to the moon."</span><span style="color: #0000FF;">}</span>
|
||||
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">hThreads</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #7060A8;">create_thread</span><span style="color: #0000FF;">(</span><span style="color: #000000;">printer</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"hd"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">hd</span><span style="color: #0000FF;">}),</span>
|
||||
<span style="color: #7060A8;">create_thread</span><span style="color: #0000FF;">(</span><span style="color: #000000;">printer</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"mg"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mg</span><span style="color: #0000FF;">})}</span>
|
||||
<span style="color: #7060A8;">wait_thread</span><span style="color: #0000FF;">(</span><span style="color: #000000;">hThreads</span><span style="color: #0000FF;">)</span>
|
||||
<!--
|
||||
6
Task/Rendezvous/PicoLisp/rendezvous-1.l
Normal file
6
Task/Rendezvous/PicoLisp/rendezvous-1.l
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
(de rendezvous (Pid . Exe)
|
||||
(when
|
||||
(catch '(NIL)
|
||||
(tell Pid 'setq 'Rendezvous (lit (eval Exe)))
|
||||
NIL )
|
||||
(tell Pid 'quit @) ) ) # Raise caught error in caller
|
||||
56
Task/Rendezvous/PicoLisp/rendezvous-2.l
Normal file
56
Task/Rendezvous/PicoLisp/rendezvous-2.l
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
(de printLine (Str)
|
||||
(cond
|
||||
((gt0 *Ink) (prinl *ID ": " Str) (dec '*Ink))
|
||||
(*Backup (rendezvousPrint @ Str) T)
|
||||
(T (quit "Out of Ink")) ) )
|
||||
|
||||
(de rendezvousPrint (Printer Str)
|
||||
(let Rendezvous NIL
|
||||
(tell Printer 'rendezvous *Pid 'printLine Str) # Call entry point
|
||||
(unless (wait 6000 Rendezvous) # Block max. 1 minute
|
||||
(quit "Rendezvous timed out") ) ) )
|
||||
|
||||
# Start RESERVE printer process
|
||||
(unless (setq *ReservePrinter (fork))
|
||||
(setq *ID 2 *Ink 5)
|
||||
(wait) ) # Run forever
|
||||
|
||||
# Start MAIN printer process
|
||||
(unless (setq *MainPrinter (fork))
|
||||
(setq *ID 1 *Ink 5 *Backup *ReservePrinter)
|
||||
(wait) )
|
||||
|
||||
# Start Humpty Dumpty process
|
||||
(unless (fork)
|
||||
(when
|
||||
(catch '(NIL)
|
||||
(for Line
|
||||
(quote
|
||||
"Humpty Dumpty sat on a wall."
|
||||
"Humpty Dumpty had a great fall."
|
||||
"All the king's horses and all the king's men"
|
||||
"Couldn't put Humpty together again." )
|
||||
(rendezvousPrint *MainPrinter Line) ) )
|
||||
(prinl " Humpty Dumpty: " @ "!") )
|
||||
(bye) )
|
||||
|
||||
# Start Mother Goose process
|
||||
(unless (fork)
|
||||
(when
|
||||
(catch '(NIL)
|
||||
(for Line
|
||||
(quote
|
||||
"Old Mother Goose"
|
||||
"When she wanted to wander,"
|
||||
"Would ride through the air"
|
||||
"On a very fine gander."
|
||||
"Jack's mother came in,"
|
||||
"And caught the goose soon,"
|
||||
"And mounting its back,"
|
||||
"Flew up to the moon." )
|
||||
(rendezvousPrint *MainPrinter Line) ) )
|
||||
(prinl " Mother Goose: " @ "!") )
|
||||
(bye) )
|
||||
|
||||
# Prepare to terminate all processes upon exit
|
||||
(push '*Bye '(tell 'bye))
|
||||
78
Task/Rendezvous/Python/rendezvous.py
Normal file
78
Task/Rendezvous/Python/rendezvous.py
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
"""An approximation of the rendezvous pattern found in Ada using asyncio."""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
|
||||
from typing import Optional
|
||||
from typing import TextIO
|
||||
|
||||
|
||||
class OutOfInkError(Exception):
|
||||
"""Exception raised when a printer is out of ink."""
|
||||
|
||||
|
||||
class Printer:
|
||||
def __init__(self, name: str, backup: Optional[Printer]):
|
||||
self.name = name
|
||||
self.backup = backup
|
||||
|
||||
self.ink_level: int = 5
|
||||
self.output_stream: TextIO = sys.stdout
|
||||
|
||||
async def print(self, msg):
|
||||
if self.ink_level <= 0:
|
||||
if self.backup:
|
||||
await self.backup.print(msg)
|
||||
else:
|
||||
raise OutOfInkError(self.name)
|
||||
else:
|
||||
self.ink_level -= 1
|
||||
self.output_stream.write(f"({self.name}): {msg}\n")
|
||||
|
||||
|
||||
async def main():
|
||||
reserve = Printer("reserve", None)
|
||||
main = Printer("main", reserve)
|
||||
|
||||
humpty_lines = [
|
||||
"Humpty Dumpty sat on a wall.",
|
||||
"Humpty Dumpty had a great fall.",
|
||||
"All the king's horses and all the king's men,",
|
||||
"Couldn't put Humpty together again.",
|
||||
]
|
||||
|
||||
goose_lines = [
|
||||
"Old Mother Goose,",
|
||||
"When she wanted to wander,",
|
||||
"Would ride through the air,",
|
||||
"On a very fine gander.",
|
||||
"Jack's mother came in,",
|
||||
"And caught the goose soon,",
|
||||
"And mounting its back,",
|
||||
"Flew up to the moon.",
|
||||
]
|
||||
|
||||
async def print_humpty():
|
||||
for line in humpty_lines:
|
||||
try:
|
||||
task = asyncio.Task(main.print(line))
|
||||
await task
|
||||
except OutOfInkError:
|
||||
print("\t Humpty Dumpty out of ink!")
|
||||
break
|
||||
|
||||
async def print_goose():
|
||||
for line in goose_lines:
|
||||
try:
|
||||
task = asyncio.Task(main.print(line))
|
||||
await task
|
||||
except OutOfInkError:
|
||||
print("\t Mother Goose out of ink!")
|
||||
break
|
||||
|
||||
await asyncio.gather(print_goose(), print_humpty())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main(), debug=True)
|
||||
61
Task/Rendezvous/Racket/rendezvous-1.rkt
Normal file
61
Task/Rendezvous/Racket/rendezvous-1.rkt
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#lang racket
|
||||
|
||||
;;; Rendezvous primitives implemented in terms of synchronous channels.
|
||||
(define (send ch msg)
|
||||
(define handshake (make-channel))
|
||||
(channel-put ch (list msg handshake))
|
||||
(channel-get handshake)
|
||||
(void))
|
||||
|
||||
(define (receive ch action)
|
||||
(match-define (list msg handshake) (channel-get ch))
|
||||
(action msg)
|
||||
(channel-put handshake 'done))
|
||||
|
||||
;;; A printer receives a line of text, then
|
||||
;;; - prints it (still ink left)
|
||||
;;; - sends it to the backup printer (if present)
|
||||
;;; - raises exception (if no ink and no backup)
|
||||
(define (printer id ink backup)
|
||||
(define (on-line-received line)
|
||||
(cond
|
||||
[(and (= ink 0) (not backup)) (raise 'out-of-ink)]
|
||||
[(= ink 0) (send backup line)]
|
||||
[else (display (~a id ":"))
|
||||
(for ([c line]) (display c))
|
||||
(newline)]))
|
||||
(define ch (make-channel))
|
||||
(thread
|
||||
(λ ()
|
||||
(let loop ()
|
||||
(receive ch on-line-received)
|
||||
(set! ink (max 0 (- ink 1)))
|
||||
(loop))))
|
||||
ch)
|
||||
|
||||
;;; Setup two printers
|
||||
|
||||
(define reserve (printer "reserve" 5 #f))
|
||||
(define main (printer "main" 5 reserve))
|
||||
|
||||
;;; Two stories
|
||||
|
||||
(define humpty
|
||||
'("Humpty Dumpty sat on a wall."
|
||||
"Humpty Dumpty had a great fall."
|
||||
"All the king's horses and all the king's men,"
|
||||
"Couldn't put Humpty together again."))
|
||||
|
||||
(define goose
|
||||
'("Old Mother Goose,"
|
||||
"When she wanted to wander,"
|
||||
"Would ride through the air,"
|
||||
"On a very fine gander."
|
||||
"Jack's mother came in,"
|
||||
"And caught the goose soon,"
|
||||
"And mounting its back,"
|
||||
"Flew up to the moon."))
|
||||
|
||||
;;; Print the stories
|
||||
(for ([l humpty]) (send main l))
|
||||
(for ([l goose]) (send main l))
|
||||
11
Task/Rendezvous/Racket/rendezvous-2.rkt
Normal file
11
Task/Rendezvous/Racket/rendezvous-2.rkt
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
main:Humpty Dumpty sat on a wall.
|
||||
main:Humpty Dumpty had a great fall.
|
||||
main:All the king's horses and all the king's men,
|
||||
main:Couldn't put Humpty together again.
|
||||
main:Old Mother Goose,
|
||||
reserve:When she wanted to wander,
|
||||
reserve:Would ride through the air,
|
||||
reserve:On a very fine gander.
|
||||
reserve:Jack's mother came in,
|
||||
reserve:And caught the goose soon,
|
||||
uncaught exception: 'out-of-ink
|
||||
52
Task/Rendezvous/Raku/rendezvous.raku
Normal file
52
Task/Rendezvous/Raku/rendezvous.raku
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
class X::OutOfInk is Exception {
|
||||
method message() { "Printer out of ink" }
|
||||
}
|
||||
|
||||
class Printer {
|
||||
has Str $.id;
|
||||
has Int $.ink = 5;
|
||||
has Lock $!lock .= new;
|
||||
has ::?CLASS $.fallback;
|
||||
|
||||
method print ($line) {
|
||||
$!lock.protect: {
|
||||
if $!ink { say "$!id: $line"; $!ink-- }
|
||||
elsif $!fallback { $!fallback.print: $line }
|
||||
else { die X::OutOfInk.new }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $printer =
|
||||
Printer.new: id => 'main', fallback =>
|
||||
Printer.new: id => 'reserve';
|
||||
|
||||
sub client ($id, @lines) {
|
||||
start {
|
||||
for @lines {
|
||||
$printer.print: $_;
|
||||
CATCH {
|
||||
when X::OutOfInk { note "<$id stops for lack of ink>"; exit }
|
||||
}
|
||||
}
|
||||
note "<$id is done>";
|
||||
}
|
||||
}
|
||||
|
||||
await
|
||||
client('Humpty', q:to/END/.lines),
|
||||
Humpty Dumpty sat on a wall.
|
||||
Humpty Dumpty had a great fall.
|
||||
All the king's horses and all the king's men,
|
||||
Couldn't put Humpty together again.
|
||||
END
|
||||
client('Goose', q:to/END/.lines);
|
||||
Old Mother Goose,
|
||||
When she wanted to wander,
|
||||
Would ride through the air,
|
||||
On a very fine gander.
|
||||
Jack's mother came in,
|
||||
And caught the goose soon,
|
||||
And mounting its back,
|
||||
Flew up to the moon.
|
||||
END
|
||||
157
Task/Rendezvous/Tcl/rendezvous.tcl
Normal file
157
Task/Rendezvous/Tcl/rendezvous.tcl
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
package require Tcl 8.6
|
||||
package require Thread
|
||||
|
||||
# Really ought to go in a package
|
||||
eval [set rendezvousEngine {
|
||||
array set Select {w {} c 0}
|
||||
|
||||
# Turns the task into a coroutine, making it easier to write in "Ada style".
|
||||
# The real thread ids are stored in shared variables.
|
||||
proc task {id script} {
|
||||
global rendezvousEngine
|
||||
set task [list coroutine RTask eval "$script;thread::exit"]
|
||||
tsv::set tasks $id [thread::create \
|
||||
"$rendezvousEngine;$task;thread::wait"]
|
||||
}
|
||||
|
||||
# A simple yielding pause.
|
||||
proc pause t {
|
||||
after $t [info coroutine]
|
||||
yield
|
||||
}
|
||||
|
||||
# Wait for a message. Note that this is *not* pretty code and doesn't do
|
||||
# everything that the Ada rendezvous does.
|
||||
proc select args {
|
||||
global Select
|
||||
set var [namespace which -variable Select](m[incr Select(c)])
|
||||
set messages {}
|
||||
foreach {message vars body} $args {
|
||||
dict set messages $message $body
|
||||
dict set bindings $message $vars
|
||||
}
|
||||
lappend Select(w) [list $var [dict keys $messages]]
|
||||
try {
|
||||
set Master ""
|
||||
while {$Master eq ""} {
|
||||
set Master [yield]
|
||||
}
|
||||
lassign $Master message responder payload
|
||||
foreach vbl [dict get $bindings $message] value $payload {
|
||||
upvar 1 $vbl v
|
||||
set v $value
|
||||
}
|
||||
set body [dict get $messages $message]
|
||||
set code [uplevel 1 [list catch $body ::Select(em) ::Select(op)]]
|
||||
set opts $Select(op)
|
||||
if {$code == 1} {
|
||||
dict append opts -errorinfo \
|
||||
"\n while processing message\n$message $payload"
|
||||
}
|
||||
set $responder [list $code $Select(em) $opts]
|
||||
} finally {
|
||||
catch {unset $var}
|
||||
set Select(w) [lrange $Select(w) 0 end-1]
|
||||
}
|
||||
}
|
||||
|
||||
# This acts as a receiver for messages, feeding them into the waiting
|
||||
# [select]. It is incomplete as it should (but doesn't) queue messages that
|
||||
# can't be received currently.
|
||||
proc receive {message args} {
|
||||
global Select
|
||||
lassign [lindex $Select(w) end] var messages
|
||||
if {$message ni $messages} {
|
||||
throw BAD_MESSAGE "don't know message $message"
|
||||
}
|
||||
set responder [namespace which -variable Select](r[incr Select(c)])
|
||||
set $responder ""
|
||||
RTask [list $message $responder $args]
|
||||
set response [set $responder]
|
||||
unset responder
|
||||
after 1
|
||||
return $response
|
||||
}
|
||||
|
||||
# This dispatches a message to a task in another thread.
|
||||
proc send {target message args} {
|
||||
after 1
|
||||
set t [tsv::get tasks $target]
|
||||
if {![thread::send $t [list receive $message {*}$args] response]} {
|
||||
lassign $response code msg opts
|
||||
return -options $opts $msg
|
||||
} else {
|
||||
return -code error $response
|
||||
}
|
||||
}
|
||||
}]
|
||||
|
||||
# The backup printer task.
|
||||
task BackupPrinter {
|
||||
set n 5
|
||||
while {$n >= 0} {
|
||||
select Print msg {
|
||||
if {$n > 0} {
|
||||
incr n -1
|
||||
puts Backup:$msg
|
||||
} else {
|
||||
throw OUT_OF_INK "out of ink"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# The main printer task.
|
||||
task MainPrinter {
|
||||
set n 5
|
||||
set Backup BackupPrinter
|
||||
while 1 {
|
||||
select Print msg {
|
||||
try {
|
||||
if {$n > 0} {
|
||||
incr n -1
|
||||
puts Main:$msg
|
||||
} elseif {$Backup ne ""} {
|
||||
send $Backup Print $msg
|
||||
} else {
|
||||
throw OUT_OF_INK "out of ink"
|
||||
}
|
||||
} trap OUT_OF_INK {} {
|
||||
set Backup ""
|
||||
throw OUT_OF_INK "out of ink"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Tasks that generate messages to print.
|
||||
task HumptyDumpty {
|
||||
pause 100
|
||||
try {
|
||||
send MainPrinter Print "Humpty Dumpty sat on a wall."
|
||||
send MainPrinter Print "Humpty Dumpty had a great fall."
|
||||
send MainPrinter Print "All the King's horses and all the King's men"
|
||||
send MainPrinter Print "Couldn't put Humpty together again."
|
||||
} trap OUT_OF_INK {} {
|
||||
puts "Humpty Dumpty out of ink!"
|
||||
}
|
||||
}
|
||||
task MotherGoose {
|
||||
pause 100
|
||||
try {
|
||||
send MainPrinter Print "Old Mother Goose"
|
||||
send MainPrinter Print "When she wanted to wander,"
|
||||
send MainPrinter Print "Would ride through the air"
|
||||
send MainPrinter Print "On a very fine gander."
|
||||
send MainPrinter Print "Jack's mother came in,"
|
||||
send MainPrinter Print "And caught the goose soon,"
|
||||
send MainPrinter Print "And mounting its back,"
|
||||
send MainPrinter Print "Flew up to the moon."
|
||||
} trap OUT_OF_INK {} {
|
||||
puts "Mother Goose out of ink!"
|
||||
}
|
||||
}
|
||||
|
||||
# Wait enough time for the example to run and then finish
|
||||
after 1000
|
||||
thread::broadcast thread::exit
|
||||
72
Task/Rendezvous/Wren/rendezvous.wren
Normal file
72
Task/Rendezvous/Wren/rendezvous.wren
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
class Printer {
|
||||
construct new(id, ink) {
|
||||
_id = id
|
||||
_ink = ink
|
||||
}
|
||||
|
||||
ink { _ink }
|
||||
ink=(v) { _ink = v }
|
||||
|
||||
print(text) {
|
||||
System.write("%(_id): ")
|
||||
for (c in text) System.write(c)
|
||||
System.print()
|
||||
_ink = _ink - 1
|
||||
}
|
||||
}
|
||||
|
||||
var ptrMain = Printer.new("Main ", 5)
|
||||
var ptrReserve = Printer.new("Reserve", 5)
|
||||
|
||||
var hd = [
|
||||
"Humpty Dumpty sat on a wall.",
|
||||
"Humpty Dumpty had a great fall.",
|
||||
"All the king's horses and all the king's men",
|
||||
"Couldn't put Humpty together again."
|
||||
]
|
||||
|
||||
var mg = [
|
||||
"Old Mother Goose",
|
||||
"When she wanted to wander,",
|
||||
"Would ride through the air",
|
||||
"On a very fine gander.",
|
||||
"Jack's mother came in,",
|
||||
"And caught the goose soon,",
|
||||
"And mounting its back,",
|
||||
"Flew up to the moon."
|
||||
]
|
||||
|
||||
var task = Fn.new { |name|
|
||||
var lines = (name == "Humpty Dumpty") ? hd : mg
|
||||
for (line in lines) {
|
||||
if (ptrMain.ink > 0) {
|
||||
ptrMain.print(line)
|
||||
Fiber.yield()
|
||||
} else if (ptrReserve.ink > 0) {
|
||||
ptrReserve.print(line)
|
||||
Fiber.yield()
|
||||
} else {
|
||||
Fiber.abort("ERROR : Reserve printer ran out of ink in %(name) task.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var rhymes = ["Humpty Dumpty", "Mother Goose"]
|
||||
var tasks = List.filled(2, null)
|
||||
for (i in 0..1) {
|
||||
tasks[i] = Fiber.new(task)
|
||||
tasks[i].call(rhymes[i])
|
||||
}
|
||||
|
||||
while (true) {
|
||||
for (i in 0..1) {
|
||||
if (!tasks[i].isDone) {
|
||||
var error = tasks[i].try()
|
||||
if (error) {
|
||||
System.print(error)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tasks.all { |task| task.isDone }) return
|
||||
}
|
||||
34
Task/Rendezvous/Zkl/rendezvous-1.zkl
Normal file
34
Task/Rendezvous/Zkl/rendezvous-1.zkl
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
class OutOfInk(Exception.IOError){
|
||||
const TEXT="Out of ink";
|
||||
text=TEXT; // rename IOError to OutOfInk for this first/mother class
|
||||
fcn init{ IOError.init(TEXT) } // this renames instances
|
||||
}
|
||||
class Printer{
|
||||
var id, ink;
|
||||
fcn init(_id,_ink){ id,ink=vm.arglist }
|
||||
fcn print(line){
|
||||
if(not ink) throw(OutOfInk);
|
||||
println("%s: %s".fmt(id,line));
|
||||
Atomic.sleep((0.0).random(0.01)); // don't let one thread dominate
|
||||
ink-=1;
|
||||
}
|
||||
}
|
||||
class RendezvousPrinter{ // the choke point between printers and tasks
|
||||
var printers=Thread.List(); // a thread safe list
|
||||
fcn init(_printers){ printers.extend(vm.arglist) }
|
||||
fcn print(line){ // caller waits for print job to finish
|
||||
var lines=Thread.List(); // fcn local [static] variable, the print queue
|
||||
lines.write(line); // thread safe, stalls when full
|
||||
// lines is racy - other threads are modifing it, length is suspect here
|
||||
while(True){ // this thread can print that threads job
|
||||
critical{ // creates a [global] mutex, automatically unlocks on exception
|
||||
if(not printers) throw(OutOfInk); // No more printers to try
|
||||
if(not lines) break; // only remove jobs in this serialized section
|
||||
try{
|
||||
printers[0].print(lines[0]); // can throw
|
||||
lines.del(0); // successful print, remove job from queue
|
||||
}catch(OutOfInk){ printers.del(0) } // Switch to the next printer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
20
Task/Rendezvous/Zkl/rendezvous-2.zkl
Normal file
20
Task/Rendezvous/Zkl/rendezvous-2.zkl
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
fcn printTask(taskNm,rendezvous,lines){
|
||||
try{ foreach line in (vm.arglist[2,*]){ rendezvous.print(line); } }
|
||||
catch{ println(taskNm," caught ",__exception); } // and thread quits trying to print
|
||||
}
|
||||
fcn humptyDumptyTask(rendezvous){ // a thread
|
||||
printTask("humptyDumptyTask",rendezvous,
|
||||
"Humpty Dumpty sat on a wall.",
|
||||
"Humpty Dumpty had a great fall.",
|
||||
"All the king's horses and all the king's men,",
|
||||
"Couldn't put Humpty together again."
|
||||
)
|
||||
}
|
||||
fcn motherGooseTask(rendezvous){ // a thread
|
||||
printTask("motherGooseTask",rendezvous,
|
||||
"Old Mother Goose,", "When she wanted to wander,",
|
||||
"Would ride through the air,", "On a very fine gander.",
|
||||
"Jack's mother came in,", "And caught the goose soon,",
|
||||
"And mounting its back,", "Flew up to the moon."
|
||||
)
|
||||
}
|
||||
5
Task/Rendezvous/Zkl/rendezvous-3.zkl
Normal file
5
Task/Rendezvous/Zkl/rendezvous-3.zkl
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
rendezvous:=RendezvousPrinter(Printer("main",5), Printer("reserve",5));
|
||||
humptyDumptyTask.launch(rendezvous);
|
||||
motherGooseTask.launch(rendezvous);
|
||||
|
||||
Atomic.waitFor(fcn{ (not vm.numThreads) }); // wait for threads to finish
|
||||
Loading…
Add table
Add a link
Reference in a new issue