2017-11-02 11 views
1

私はErlangの新しい学習者です。Erlang変数のライフサイクルについて質問があります。 Erlang gen_server comunicationgen_serverの状態ライフサイクルは何ですか

-module(wy). 
-compile(export_all). 
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). 
-behaviour(gen_server). 
-record(state, {id ,m, succ, pred}). 

start(Name, M) -> 
    gen_server:start_link({local, Name}, ?MODULE, [Name, M], []). 

init([Name, M]) -> 
    {ok, #state{id = Name, m = M}}. 

handle_call({get_server_info}, _Frome, State) -> 
    {reply, State, State}; 
handle_call(_Request, _From, State) -> 
    Reply = ok, 
    {reply, Reply, State}. 

handle_cast(_Msg, State) -> 
    {noreply, State}. 

handle_info(_Info, State) -> 
    {noreply, State}. 

terminate(_Reason, _State) -> 
    ok. 

code_change(_OldVsn, State, _Extra) -> 
    {ok, State}. 


get_server_info(ServerName) -> 
    gen_server:call(ServerName, {get_server_info}). 

から

リファレンス変数 "状態" のライフサイクルとは何ですか?

変数「状態」がhandle_callおよびhandle_castから再利用されていることがわかります。まず、これらの "State"はinit()関数"#state{id = Name, m = M}"から初期化されたものと同じですか?

もしそうなら、この "状態"はグローバル変数ですか?この "状態"はいつ破壊されるのでしょうか?

Erlangにはグローバル変数がありますか?

答えて

4

あなたの直感は、正しいです。それぞれのコールバック(inti/1handle_call/3など)はStateをパラメータとして受け取って、結果の一部として(おそらく新しい)Stateを返す必要があります。

この機能の仕組みを理解するには、gen_serverの機能を理解する必要があります。あなたがgen_server:start_link/4を呼び出すときに超非常に-単純化方法で、どのようなgen_serverがやっているです:

% Ignoring stuff here, for simplicity 
start_link(_Name, Mod, InitArg, _Options) -> 
    spawn(
    fun() -> 
     {ok, State} = Mod:init(InitArg), 
     loop(Mod, State) %% This is where the result of your init/1 function goes 
    end). 

loop(Mod, State) -> 
    NextState = 
    receive 
     {call, From, Msg} -> 
     % Here, it gives you the current state and expects you to return 
     % a new one. 
     {reply, Reply, NewState} = Mod:handle_call(Msg, From, State), 
     NewState; 
     {cast, Msg} -> 
     % Here, it gives you the current state and expects you to return 
     % a new one. 
     {noreply, NewState} = Mod:handle_cast(Msg, State), 
     NewState; 
     Info -> 
     % Here, it gives you the current state and expects you to return 
     % a new one. 
     {noreply, NewState} = Mod:handle_info(Msg, State), 
     NewState; 
     {stop, Reason} -> 
     Mod:terminate(Reason, State), 
     exit(Reason) 
    end, 
    loop(Mod, NextState). % Then it keeps on looping with the new state 

あなたが見ることができるように、Stateの値はgen_serverプロセスに対してローカルである、それは、各コールバックに渡され、 に置き換えられ、各コールバックの結果がサーバーが終了するまでループし続けることになります。 もちろん、gen_serverのコードはそれほど単純ではありません(This talkは、これについて大きな説明をしています - スペイン語で、わかります、残念です)。

希望します。

+0

ありがとう、Brujo。私はもう1つのフォローアップの質問があります。コール、キャスト、情報、状態を異なるプロセスから同時に設定すると、状態は異なるプロセスのすべての変更をキャプチャしますか? cast()が値AをStateに設定すると同時に、別のcast()は値BをStateに設定します。その前にStateは空です。値の設定後、State、A、B、またはABのどちらに保存されますか? @Brujo Benavides – Neil

+0

ええ、私のコードで見ることができるように、たとえメッセージがサーバーに非同期で到達したとしても、ループはその時に1つのみを処​​理し、各コールバックの評価は同期的です(つまり、何かが返されるまで'handle_ *'から)。 また、明白にするために、 'gen_server:cast/2'は状態を設定せず、サーバプロセスにのみメッセージを送信します。この例では、 'cast(Server、Msg) - > Serverのように見えます。 {cast、Msg}。 そのメッセージは 'loop'内で受信され、' Mod:handle_cast/2'が評価されるときです。 –

0

は、gen_serverの内部状態です。状態は何でもかまいません。データ構造(マップ、レコードまたはリスト)への単一変数、この場合はレコードです。値のセットを定義している場合はレコードを使用し、それ以外の場合はマップを使用できます。

はい、状態はinit()関数で初期化され、各コールバックのパラメータとして渡されます。必要に応じて状態値を更新するだけで、各コールバックで応答を送信するときの新しい状態を設定できます。

genサーバーが正常に終了または終了すると、状態はgen_serverプロセスとともに破棄されます。理由付きで終了するときに通常の終了/ 3コールバックが呼び出されます。私はそれが変数Stateはどこでも同じ技術的にではないことを指摘する価値があると思いますが、それはどこでも同じを参照んが

関連する問題