Se si sta tentando una simulazione, sarà necessario un maggiore controllo sui nodi rispetto al semplice utilizzo dei thread consentirà di eseguire — o almeno senza problemi.
Il mio approccio soggettivo all'argomento sarebbe quello di creare una macchina virtuale semplice a thread singolo per mantenere il pieno controllo della simulazione. Il modo più semplice per farlo in OCaml è quello di utilizzare una struttura monade-simile (come avviene in LWT, per esempio):
(* A thread is a piece of code that can be executed to perform some
side-effects and fork zero, one or more threads before returning.
Some threads may block when waiting for an event to happen. *)
type thread = < run : thread list ; block : bool >
(* References can be used as communication channels out-of-the box (simply
read and write values ot them). To implement a blocking communication
pattern, use these two primitives: *)
let write r x next = object (self)
method block = !r <> None
method run = if self # block then [self]
else r := Some x ; [next()]
end
let read r next = object (self)
method block = !r = None
method run = match r with
| None -> [self]
| Some x -> r := None ; [next x]
end
È possibile creare primitive meglio adatto alle vostre esigenze, come ad esempio l'aggiunta di un "tempo necessario per trasmettere "proprietà nei tuoi canali.
Il passaggio successivo è la definizione di un motore di simulazione.
(* The simulation engine can be implemented as a simple queue. It starts
with a pre-defined set of threads and returns when no threads are left,
or when all threads are blocking. *)
let simulate threads =
let q = Queue.create() in
let() = List.iter (fun t -> Queue.push t q) threads in
let rec loop blocking =
if Queue.is_empty q then `AllThreadsTerminated else
if Queue.length q = blocking then `AllThreadsBlocked else
let thread = Queue.pop q in
if thread # block then (
Queue.push thread q ;
loop (blocking + 1)
) else (
List.iter (fun t -> Queue.push t q) (thread # run) ;
loop 0
)
in
loop 0
Nuovamente, si può regolare il motore per tenere traccia di quale nodo sta eseguendo quale thread, per mantenere le priorità per-nodo in modo da simulare un nodo essendo massicciamente lento o più veloce rispetto ad altri, o raccogliendo casualmente un filo per l'esecuzione su ogni passaggio e così via.
L'ultimo passaggio è l'esecuzione di una simulazione. Qui, avrò due thread che inviano numeri casuali avanti e indietro.
let rec thread name input output =
write output (Random.int 1024) (fun() ->
read input (fun value ->
Printf.printf "%s : %d" name value ;
print_newline() ;
thread name input output
))
let a = ref None and b = ref None
let _ = simulate [ thread "A -> B" a b ; thread "B -> A" b a ]
fonte
2012-02-13 18:08:40
Questa è una risposta fantastica, molto stimolante. – Tiemen