|
| 1 | +%% can be run via escript if desired... |
| 2 | +-module(ring). |
| 3 | + |
| 4 | +-export([main/1]). |
| 5 | + |
| 6 | +-record(opts, { |
| 7 | + ring_size = 1 :: non_neg_integer(), |
| 8 | + iterations = 1 :: non_neg_integer() |
| 9 | +}). |
| 10 | + |
| 11 | +main(Argv) when is_list(Argv) -> |
| 12 | + Opts = parse_args(Argv), |
| 13 | + {Time, ok} = timer:tc(fun() -> run(Opts) end), |
| 14 | + io:format("elapsed (wallclock) time: ~pms~n", [Time / 1000]). |
| 15 | + |
| 16 | +run(#opts{ ring_size=RingSize, iterations=SendCount }) -> |
| 17 | + Self = self(), |
| 18 | + Msg = {"foobar", "baz"}, |
| 19 | + Pid = make_ring(RingSize, Self), |
| 20 | + [Pid ! Msg || _ <- lists:seq(1, SendCount)], |
| 21 | + collect(SendCount). |
| 22 | + |
| 23 | +collect(0) -> |
| 24 | + ok; |
| 25 | +collect(N) -> |
| 26 | + receive |
| 27 | + {"foobar", "baz"} -> collect(N - 1); |
| 28 | + Other -> exit({unexpected_message, Other}) |
| 29 | + end. |
| 30 | + |
| 31 | +-spec(make_ring(integer(), pid()) -> pid()). |
| 32 | +make_ring(0, NextPid) -> |
| 33 | + go(NextPid); |
| 34 | +make_ring(NumProcs, NextPid) -> |
| 35 | + make_ring(NumProcs - 1, go(NextPid)). |
| 36 | + |
| 37 | +-spec(go(pid()) -> pid()). |
| 38 | +go(NextPid) -> |
| 39 | + spawn(fun() -> relay(NextPid) end). |
| 40 | + |
| 41 | +-spec(relay(pid()) -> no_return()). |
| 42 | +relay(NextPid) -> |
| 43 | + receive |
| 44 | + {_, _}=Msg -> NextPid ! Msg, relay(NextPid) |
| 45 | + end. |
| 46 | + |
| 47 | +-spec(parse_args([string()]) -> #opts{}). |
| 48 | +parse_args(Argv) -> |
| 49 | + lists:foldl(fun parse_args/2, #opts{}, Argv). |
| 50 | + |
| 51 | +parse_args(("-r" ++ Val), Opts) -> |
| 52 | + Sz = check_positive(ring_size, list_to_integer(Val)), |
| 53 | + Opts#opts{ ring_size = Sz }; |
| 54 | +parse_args(("-i" ++ Val), Opts) -> |
| 55 | + Iter = check_positive(iterations, list_to_integer(Val)), |
| 56 | + Opts#opts{ iterations = Iter }. |
| 57 | + |
| 58 | +check_positive(K, N) when N < 1 -> |
| 59 | + io:format("~p must be >= 1~n", [K]), |
| 60 | + error({K, N}); |
| 61 | +check_positive(_, N) -> |
| 62 | + N. |
0 commit comments