2012年2月18日土曜日

Erlang 2プロセスでフィボナッチ数計算

Erlangで2プロセス(Erlangの軽量プロセスのこと)起動し、それぞれのプロセスがhandler_loop(count_loop)から自然数を取得し、39までのフィボナッチ数を計算する。

1つのプロセスが自然数Nのフィボナッチ数を計算し始めたら、もうひとつのプロセスはN+1を計算します。

なぜこんなことをしたかというと、Cでスレッドおよびmutexロックの勉強をしていて、おなじプログラムを組んだため、それをErlangでやってみました。

Erlangプログラムの概要を図にしました。

□ソース

-module(thread_fib).
-compile(export_all).

-define( _fini, finish ).
-define( _MAX, 40 ).
start() ->
    Pid = self(),
    Pid_count   = spawn( thread_fib, handler_loop, [ Pid ] ),
    Pid1        = spawn( thread_fib, handler_fib, [ Pid, Pid_count, "proc_a" ] ),
    Pid2        = spawn( thread_fib, handler_fib, [ Pid, Pid_count, "proc_b" ] ),
    wait( ).

wait( ) ->
    receive
        ?_fini -> io:format( "start() end." )
    end.

handler_loop( Pid ) ->
    count_loop( Pid, 0, 0 ).

count_loop( StartPid, N, FiniCount ) ->
    receive
        { count, Pid } ->
            Pid ! { count, N },
            count_loop( StartPid, N + 1, FiniCount );
        ?_fini -> case FiniCount < 1 of
                    true  -> count_loop( StartPid, N, FiniCount + 1 );
                    false -> StartPid ! ?_fini
                  end
    end.

handler_fib( Pid1, Pid2, Proc ) ->
    fib_proc( Pid2, Proc ).

fib_proc( Pid, Proc ) ->
    Pid ! { count, self() },
    receive
        { count, N } ->
            case N < ?_MAX of
                true    ->  Fib = fib( N ),
                            io:format( "~p(~p)=(~p)~n", [ Proc, N, Fib ] ),
                            fib_proc( Pid, Proc );
                false   ->  Pid ! ?_fini,
                            io:format( "End ~p~n", [ Proc ] )
            end
    end.


fib( 0 ) -> 1;
fib( 1 ) -> 1;
fib( N ) -> fib( N - 1 ) + fib( N - 2 ).