Si va a intentar una simulación, necesitará mucho más control sobre sus nodos que simplemente usar hilos permitirá — o al menos, sin mayores inconvenientes.
Mi enfoque subjetivo sobre el tema sería crear una máquina virtual simple de un solo hilo para mantener el control total de la simulación. La forma más fácil de hacerlo en OCaml es utilizar una estructura mónada similar (como se hace en peso liviano, por ejemplo):
(* 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
Puede crear mejores primitivas que se adapten a sus necesidades, tales como la adición de un "tiempo requerido para transmitir "propiedad en sus canales.
El siguiente paso es definir un motor de simulación.
(* 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
Una vez más, es posible ajustar el motor para realizar un seguimiento de lo que el nodo está ejecutando por cuál de ellos, para mantener las prioridades por nodo con el fin de simular un nodo de ser masivamente más lento o más rápido que otros, o escoger al azar un hilo para la ejecución en cada paso, y así sucesivamente.
El último paso es ejecutar una simulación. Aquí, voy a tener dos hilos que envían números aleatorios de un lado a otro.
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 ]
Esa es una respuesta increíble, muy inspiradora. – Tiemen