http://www.mcs.anl.gov/research/projects/mpi/tutorial/mpiexmpl/src/ring/C/main.html
Write a program that takes data from process zero and sends it to all of the other processes by sending it in a ring. That is, process i should receive the data and send it to process i+1, until the last process is reached.
la solucion en C salio bastante facil haciendo copypasta de los problemas anteriores y sorprendentemente en este caso los otros procesos si imprimieron a la consola:
#include <stdio.h>
#include <mpi.h>
int main (int argc, char** argv) {
int rank, size, value, i;
MPI_Status status;
MPI_Init (&argc, &argv); /* starts MPI */
MPI_Comm_rank (MPI_COMM_WORLD, &rank); /* get current process id */
MPI_Comm_size (MPI_COMM_WORLD, &size); /* get number of processes */
do {
if(rank == 0) {
printf("give me a value: ");
scanf("%d", &value);
fflush(stdout);
MPI_Send(&value, 1, MPI_INT, rank + 1, 1, MPI_COMM_WORLD);
}
else{
MPI_Recv(&value, 1, MPI_INT, rank - 1, 1, MPI_COMM_WORLD, &status);
printf("process %d received %d\n", rank, value);
if(rank + 1 < size) {
printf("sending to %d\n", rank + 1, value);
MPI_Send(&value, 1, MPI_INT, rank + 1, 1, MPI_COMM_WORLD);
}
fflush(stdout);
}
} while(value >= 0);
printf("negative value, closing\n");
MPI_Finalize();
return 0;
}
la solucion en erlang (tambien robando del ejercicio anterior):
-module(ej5).
-export([run/1]).
run(Total) ->
NextPid = spawn_listeners(Total),
get_values(NextPid).
spawn_listeners(Count) -> spawn_listeners(Count, none).
spawn_listeners(0, NextPid) -> NextPid;
spawn_listeners(Count, LastPid) ->
NextPid = spawn(fun() -> listener(LastPid) end),
spawn_listeners(Count - 1, NextPid).
listener(NextPid) ->
receive
Int ->
io:format("process ~p received ~p~n", [self(), Int]),
if
NextPid /= none ->
io:format("sending to ~p~n", [NextPid]),
NextPid ! Int;
true -> ok
end,
if
Int >= 0 -> listener(NextPid);
true ->
io:format("negative value, closing ~p~n", [self()])
end
end.
get_value(Message, ConversionFun) ->
case io:get_line(Message) of
{error, Reason} -> {error, Reason};
eof -> {error, eof};
Value -> ConversionFun(Value)
end.
get_values(NextPid) ->
case get_value("give me an int value (negative to quit): ", fun(Val) -> string:to_integer(Val) end) of
{error, Reason} ->
io:format("error reading int value (~p)~n", [Reason]),
get_values(NextPid);
{IntValue, _Rest} ->
io:format("sending to ~p~n", [NextPid]),
NextPid ! IntValue,
if
IntValue >= 0 -> get_values(NextPid);
true -> io:format("negative value, closing~n")
end
end.
ejemplo de salida:
$ erl
Erlang (BEAM) emulator version 5.6.5 [source] [async-threads:0] [kernel-poll:false]
Eshell V5.6.5 (abort with ^G)
1> c(ej5).
{ok,ej5}
2> ej5:run(3).
give me an int value (negative to quit): 3
sending to <0.40.0>
process <0.40.0> received 3
sending to <0.39.0>
process <0.39.0> received 3
sending to <0.38.0>
process <0.38.0> received 3
give me an int value (negative to quit): asd
error reading int value (no_integer)
give me an int value (negative to quit): 42
sending to <0.40.0>
process <0.40.0> received 42
sending to <0.39.0>
process <0.39.0> received 42
sending to <0.38.0>
process <0.38.0> received 42
give me an int value (negative to quit): -1
sending to <0.40.0>
negative value, closing
process <0.40.0> received -1
sending to <0.39.0>
ok
negative value, closing <0.40.0>
process <0.39.0> received -1
sending to <0.38.0>
negative value, closing <0.39.0>
process <0.38.0> received -1
negative value, closing <0.38.0>
3 comentarios:
¡Hola Mariano, cómo estás! Muy interesante los ejercicios que estás resolviendo. ¿Erlang es un lenguaje de programación tipo Ruby?
¡Saludos!
Buenas, no erlang es un lenguaje funcional orientado a la concurrencia y alta disponibilidad. En criollo significa que los programas se diseñan en base a funciones que intercambian mensajes.
no le pasa muy cerca a ruby ni a ninguno similar ya que no es orientado a objetos, de hecho no tiene variables como normalmente las conocemos tampoco ya que una variable puede ser asignada una sola vez.
Para agregarle diversión no tiene primitivas de iteracion como for y while (aunque pueden ser simuladas con recursion).
todo esto es asi para permitir escribir sistemas de alta concurrencia sin problemas como deadlocks, race conditions y problemas similares que nos trae aparejado un lenguaje con estado global o mejor dicho con shared memory.
Muy interesante. Gracias por la explicación, cuando pueda experimento un poco con el mismo.
¡Saludos! [Por cierto, estuvo buena la charla que diste la otra vez en Intel, fui parte del grupo de la profe Blanca Carrizo]
Publicar un comentario