erlang實例——los簡單實現

最近看了《erlang程序設計》,好書,翻譯的也不錯,兩天時間,基本讀完(我的習慣總是先快速讀完一本書再回過頭,一邊練習一邊翻閱),正試着學習編寫erlang的例子。Joe在網上(http://erlang.org/examples/examples-2.0.html)給了一個簡單系統(sos)的例子,可惜我太笨,怎麼都沒跑成功,又缺少專研的韌勁去弄清楚爲什麼,所以乾脆決定自己寫一個簡單的例子。

 

這個簡單的例子的基本思想就是首先,啓動一個IO進程負責io的讀寫工作(體現一切皆進程的思想,並且數據也應該是屬於進程的,io就是io進程的私有數據),再啓動一個shell負責讀寫和執行用戶的命令(不過,目前的實現只是從標準輸入讀入輸入並顯示到標準輸出,呵呵,剛起步,以後會慢慢完善)。

 

los的主文件是los.erl,其模塊聲明如下:

 

-module(los).

-export([

boot/0,

make_scripts/0,

read/0,

write/1 ]).


,比較簡單,boot/0函數啓動los,read/0、write/1從標準輸入輸出讀寫數據;至於make_scripts/0,目前還沒用到,從joe的sos拷貝過來的,等研究清楚了啓動腳本再考慮使用吧。

 

啓動los也很簡單,首先啓動erl shell,運行los:boot()就完成啓動:

 

1> los:boot().

los booted!

los_sh started!

los>

 


1.boot/0的工作就是啓動io服務進程,然後啓動shell等待用戶輸入:

 

boot() ->

start_io(),

write("los booted!~n"),

los_sh:run(),

write("los goodbye!~n").


2. start_io例程調用make_global例程來創建服務,其實現如下:

 

 

start_io() ->

make_global(io, fun io_loop/0).

 

 

3. make_global例程實現如下:

 

 

make_global(Name, Fun) ->

    case whereis(Name) of

        undefined ->

            Self = self(),

            Pid = spawn(fun() ->

                               make_global(Self,Name,Fun)

                            end),

            receive

                {Pid, ack} ->

                    Pid

            end;

        Pid ->

            Pid

    end.

 

 

make_global首先判斷Name是否已經註冊,沒有註冊,則調用spawn函數新建一個進程,並返回Pid,如果已經註冊,直接返回Pid。

 

真正註冊進程的例程是make_global/3,其代碼如下:

 

 

make_global(Pid, Name, Fun) ->

    case register(Name, self()) of

        {'EXIT', _} ->

            Pid ! {self(), ack};

        _ ->

            Pid ! {self(), ack},

            Fun()

    end.

 

 

4. boot有兩個write調用,是los提供的系統級函數。write例程的實現如下:

    

write(Str) ->

{write, Reply} = rpc(io, {write, Str}),

case Reply of 

succeed -> succeed;

_ -> failue

end.

 

  write例程就是調用rpc向io進程發送寫的消息和要寫的數據,io會將寫的狀態返回給當前進程,rpc就是向io進程發送消息並返回消息。

 

5. rpc例程的實現如下:

 

 

rpc(Name, Q) -> 

         Name ! {rpc, self(), Q},

         receive     

             {Name, Reply} ->

                 Reply;

             {Name, exit, Why} ->

                 exit(Why)

         end.

 

 

6. los還提供了read函數:

 

 

read() ->

{read, Data} = rpc(io, read),

Data.

read函數將讀到的數據傳遞給調用者。

 

 

呵呵,los還是很簡單的,需要注意的大概就是read和write的消息格式。

 

下面是los_sh模塊,很簡單:

 

 

-module(los_sh).

-export([run/0]).

 

run() ->

los:write("los_sh started!~n"),

loop().

 

loop() ->

Data = los:read(),

case lists:member({Data}, [{"q/n"},{"Q/n"},{"quit/n"},{"Quit/n"}]) of 

true -> los:write("los_sh quit!~n");

false -> los:write(Data),

loop()

end.

 

 

shell就是簡單的調用read和write讀取和顯示用戶的輸入,這並不是真正意義上的shell,下面正試着編寫一些簡單的命令,能夠在los中運行,對系統做一些文件的操作。

 

一個比較有意思的問題是,如果將模塊los_sh的名稱改爲shell,並編譯生成shell.beam,那麼啓動erl會出現問題,有一個很長的錯誤列表(我並沒有記錄錯誤日誌,不過很容易實驗)。

 

我猜想erlang的shell會尋找類似shell.beam之類的文件吧,還沒有細研究過,有哪位高人知道的,希望不吝賜教。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章