gen_server
gen_server
模块
gen_server
模块摘要
一般服务器行为。
描述
此行为模块提供客户端 - 服务器关系的服务器。gen_server
使用此模块实现的通用服务器进程()具有一组标准接口函数,并包含用于跟踪和错误报告的功能。它也适合于OTP监督树。有关更多信息,请参见gen_server Behaviour
OTP设计原则中的部分。
一个gen_server
过程假定所有特定的部分位于导出预定义函数集的回调模块中。行为函数和回调函数之间的关系如下所示:
gen_server module Callback module
----------------- ---------------
gen_server:start
gen_server:start_link -----> Module:init/1
gen_server:stop -----> Module:terminate/2
gen_server:call
gen_server:multi_call -----> Module:handle_call/3
gen_server:cast
gen_server:abcast -----> Module:handle_cast/2
- -----> Module:handle_info/2
- -----> Module:terminate/2
- -----> Module:code_change/3
如果回调函数失败或返回一个坏值,则gen_server
进程终止。
一个gen_server
进程处理系统消息,如下所述sys(3)
。该sys
模块可用于调试gen_server
进程。
请注意,一个gen_server
进程不会自动捕获出口信号,这必须在回调模块中明确启动。
除非另有说明,否则如果指定的gen_server
进程不存在或者指定的参数错误,则此模块中的所有函数都会失败。
如果回调函数指定而不是超时值,则gen_server
进程可以进入休眠状态(请参阅erlang:hibernate/3
)'hibernate'
。如果服务器预计长时间处于空闲状态,这可能很有用。但是,请谨慎使用此功能,因为休眠意味着至少需要两次垃圾回收(休眠时和唤醒后不久),并且不是每次调用繁忙服务器时都要执行的操作。
输出
abcast(Name, Request) -> abcastabcast(Nodes, Name, Request) -> abcast
类型
将异步请求发送到在指定节点上本地注册为Name的gen_server进程。 该函数立即返回并忽略不存在的节点,或者gen_server名称不存在的节点。 gen_server处理调用Module:handle_cast / 2来处理请求。
有关参数的描述,请参见multi_call/2,3,4
...
call(ServerRef, Request) -> Replycall(ServerRef, Request, Timeout) -> Reply
类型
通过发送请求并等待回复到达或发生超时ServerRef
,对gen_server
进程进行同步调用。该gen_server
进程调用Module:handle_call/3
来处理请求。
ServerRef
可以是下列任何一种:
- PID
Name
,如果gen_server
进程在本地注册
{Name,Node}
,如果gen_server
进程在另一个节点上本地注册。
{global,GlobalName}
,如果gen_server
流程在全球注册
{via,Module,ViaName}
,如果gen_server
进程通过另一个流程注册表注册。
Request
作为参数之一传递给Module:handle_call/3
...
Timeout
大于零的整数,该整数指定等待答复的毫秒数或原子。infinity
无限期的等待。默认为5000。如果在指定的时间内没有收到答复,则函数调用将失败。如果调用方捕捉到故障并继续运行,而服务器只是响应延迟,那么它可以在稍后的任何时候到达调用方的消息队列。在本例中,调用方必须为此做好准备,并丢弃任何这类垃圾消息,这些垃圾消息是两个元素元组,引用作为第一个元素。
返回值Reply在Module:handle_call / 3的返回值中定义。
该呼叫可能由于多种原因而失败,包括超时和呼叫gen_server
过程在呼叫之前或呼叫过程中死亡。
cast(ServerRef, Request) -> ok
类型
将异步请求发送到gen_server进程的ServerRef,并立即返回ok,忽略目标节点或gen_server进程是否不存在。 gen_server进程调用Module:handle_cast / 2来处理请求。
有关说明ServerRef
,请参阅call/2,3
。
Request
作为参数之一传递给Module:handle_cast/2
...
enter_loop(Module, Options, State)enter_loop(Module, Options, State, ServerName)enter_loop(Module, Options, State, Timeout)enter_loop(Module, Options, State, ServerName, Timeout)
类型
使现有流程成为gen_server
流程。不返回,而是调用进程进入gen_server
进程接收循环并成为一个gen_server
进程。该过程必须
已经开始使用其中的一个启动函数proc_lib(3)
。用户负责该过程的任何初始化,包括为其注册一个名称。
当需要比gen_server
进程行为提供。
Module
,Options
与ServerName
与调用时具有相同的含义start[_link]/3,4
。但是,如果ServerName
指定了该过程,则必须在
调用此函数之前
相应地注册该过程。
State
和Timeout
具有与返回值相同的含义Module:init/1
。回调模块Module
不需要导出init/1
功能。
如果调用进程未由proc_lib启动函数启动,或者未根据ServerName注册,则该函数失败。
multi_call(Name, Request) -> Resultmulti_call(Nodes, Name, Request) -> Resultmulti_call(Nodes, Name, Request, Timeout) -> Result
类型
通过首先向每个节点发送一个请求,然后等待回复,对在指定节点上gen_server
本地注册的所有进程进行同步调用Name
。该gen_server
进程调用Module:handle_call/3
来处理请求。
该函数返回一个元组{Replies,BadNodes}
,其中Replies
是一个列表,{Node,Reply}
并且BadNodes
是一个不存在的节点列表,或者gen_server
Name
不存在或没有回复的节点列表。
Nodes
是要将请求发送到的节点名称的列表。默认值是所有已知节点的列表[node()|nodes()]
。
Name
是每个gen_server
进程的本地注册名称。
Request
作为参数之一传递给Module:handle_call/3
...
Timeout
大于零的整数,该整数指定等待每个答复的毫秒数或原子。infinity
无限期的等待。默认为infinity
如果在指定的时间内没有收到来自节点的答复,则将该节点添加到BadNodes
...
当在节点Node处从gen_server进程接收到回复答复时,{Node,Reply}被添加到回复。 回复在Module:handle_call / 3的返回值中定义。
警告
如果其中一个节点无法处理监视器(例如C或Java节点),并且gen_server
发送请求时未启动进程,但在2秒内启动,则此函数将等待整个过程Timeout
,这可能是无限的。
如果所有节点都是Erlang节点,则不存在此问题。
为了防止在超时后(即超时之后)污染调用者的消息队列,使用中间人过程来进行呼叫。迟到的答案在到达终止的过程时被丢弃。
reply(Client, Reply) -> Result
类型
如果在Module:handle_call / 3的返回值中无法定义应答,则gen_server进程可以使用此函数显式发送应答给称为call / 2,3或multi_call / 2,3,4的客户端。
Client
必须是From
提供给回调函数的参数。Reply
是指作为call/2,3
或返回给客户的任何术语multi_call/2,3,4
。
返回值Result
没有进一步定义,并且总是被忽略。
start(Module, Args, Options) -> Resultstart(ServerName, Module, Args, Options) -> Result
类型
创建一个独立的gen_server
进程,即一个gen_server
不属于监督树的进程,因此没有主管。
有关参数和返回值的说明,请参见start_link/3,4
...
start_link(Module, Args, Options) -> Resultstart_link(ServerName, Module, Args, Options) -> Result
类型
创建一个gen_server
过程作为监督树的一部分。该职能将由主管直接或间接调用。例如,它可以确保gen_server
流程与主管链接。
gen_server进程调用Module:init / 1进行初始化。 为了确保同步启动过程,直到Module:init / 1返回后,start_link / 3,4才会返回。
- 如果
ServerName={local,Name}
该gen_server
进程在本地注册为Name
使用register/2
。
- 如果
ServerName={global,GlobalName}
,gen_server
进程id在全球注册为GlobalName
使用global:register_name/2
如果没有提供名称,则gen_server
进程未注册。
- 如果
ServerName={via,Module,ViaName}
该gen_server
进程注册到注册表所代表的Module
。该Module
回调是要导出的功能register_name/2
,unregister_name/1
,whereis_name/1
,和send/2
,这是表现得像在相应的功能global
。因此,这{via,global,GlobalName}
是一个有效的参考。Module
是回调模块的名称。Args
是作为参数传递给的任何术语Module:init/1
。
- 如果
{timeout,Time}
存在选项,gen_server
则允许进程花费Time
毫秒初始化,或者终止并启动函数返回{error,timeout}
。
- 如果
{hibernate_after,HibernateAfterTimeout}
存在选项,则gen_server
进程等待任何消息HibernateAfterTimeout
几毫秒,如果没有收到消息,进程将自动进入休眠状态(通过调用proc_lib:hibernate/3
)。
- 如果选项
{debug,Dbgs}
存在,sys
则为每个项目调用相应的函数Dbgs
; 见sys(3)
。
- 如果存在选项{spawn_opt,SOpts},则SOP作为选项列表传递给spawn_opt BIF,该BIF用于产生gen_server进程;请参阅spawn_opt / 2.注意:使用spawn选项监视器是不允许的,它会导致函数失败,原因是badarg。如果gen_server进程成功创建并初始化,函数返回{ok,Pid},其中Pid是gen_server的pid处理。如果已经存在具有指定ServerName的进程,则该函数返回{error,{already_started,Pid}},其中Pid是该进程的PID。如果Module:init / 1因Reason失败,则该函数返回{error,Reason} 。如果Module:init / 1返回{stop,Reason}或忽略,则进程终止并且函数分别返回{error,Reason}或ignore.stop(ServerRef) - > okstop(ServerRef,Reason,Timeout) - > okTypesOrders通用服务器以指定的原因退出并等待它终止。在退出之前,gen_server进程调用Module:terminate / 2。如果服务器以期望的原因终止,函数返回ok。除正常,关机或{shutdown,Term}之外的任何其他原因都会导致使用error_logger:format / 2发出错误报告。默认的Reason是normal.Timeout是一个大于零的整数,指定等待服务器终止的毫秒数,或无限等待的原子无穷大。默认为无穷大。如果服务器没有在指定时间内终止,则会引发超时异常。如果该过程不存在,则会引发noproc异常。回调函数以下函数将从gen_server回调模块导出.ExportsModule:code_change(OldVsn,状态,额外) - > {ok,NewState} | {error,Reason} TypesNoteThis回调是可选的,所以回调模块不需要导出它。如果在未实现code_change / 3的情况下,在appup文件中指定的Change = {advanced,Extra}发行升级/降级时,该进程将会崩溃并出现undef退出原因。该函数在gen_server进程在发布升级/降级期间更新其内部状态,也就是说,在appup文件中指定了{update,Module,Change,...},其中Change = {advanced,Extra}。有关更多信息,请参见释放OTP设计原则中的处理指令。升级时,OldVsn为Vsn,对于降级,OldVsn为{down,Vsn}。 Vsn由回调模块Module的旧版本的vsn属性定义。如果没有定义这样的属性,版本就是Beam文件的校验和.State是gen_server进程的内部状态.Extra从更新指令的{advanced,Extra}部分按原样传递。如果成功,该函数必须返回更新的内部状态。如果函数返回{error,Reason},则正在进行的升级失败并回滚到旧版本。模块:format_status(Opt,[PDict,State]) - > StatusTypes注意此回调是可选的,所以回调模块不需要导出它。 gen_server模块提供了该函数的默认实现,该函数返回回调模块的状态。在下列情况下,该函数由gen_server进程调用:
- sys之一:get_status / 1,2被调用来获取gen_server状态。 Opt设置为原子法线。
- gen_server进程异常终止并记录错误。 Opt设置为原子终止。此功能对于更改这些情况下gen_server状态的形式和外观很有用。希望更改sys:get_status / 1,2返回值的回调模块,以及其状态在终止错误日志中的显示方式将导出format_status / 2实例,该实例返回描述gen_server进程当前状态的术语.PDict是gen_server进程的进程字典的当前值.State是gen_server进程的内部状态。该函数用于返回Status,这是一个用于更改gen_server进程的当前状态和状态的详细信息的术语。状态可以采用的形式没有限制,但对于sys:get_status / 1,2的情况(当Opt正常时),状态值的推荐形式为[{data,[{“State”,Term}] }],其中Term提供了gen_server状态的相关细节。遵循这个建议并不是必需的,但它使得回调模块状态与sys:get_status / 1,2返回值的其余部分保持一致。此函数的一个用途是返回紧凑的替代状态表示以避免打印大状态项在日志文件中。模块:handle_call(Request,From,State) - > ResultTypes当gen_server进程接收到使用call / 2,3或multi_call / 2,3,4发送的请求时,将调用该函数来处理请求.Request is提供给call或multi_call.From的Request参数是一个元组{Pid,Tag},其中Pid是客户端的pid,Tag是唯一的标记.State是gen_server进程的内部状态。
- 如果
{reply,Reply,NewState}
返回,{reply,Reply,NewState,Timeout}
或者{reply,Reply,NewState,hibernate}
,Reply
返还给From
作为返回值call/2,3
或包含在返回值multi_call/2,3,4
。该gen_server
过程然后继续以可能更新的内部状态执行NewState
。
有关说明Timeout
和hibernate
见Module:init/1
。
- 如果
{noreply,NewState}
返回,{noreply,NewState,Timeout}
或者{noreply,NewState,hibernate}
,gen_server
过程继续执行NewState
。任何回复都From
必须使用明确指定reply/2
。
- 如果
{stop,Reason,Reply,NewState}
被归还,Reply
被还给From
...
- 如果返回{stop,Reason,NewState},则必须使用reply / 2明确指定对From的任何答复。然后gen_server进程调用Module:terminate(Reason,NewState)和terminates.Module:handle_cast(Request,State) - > ResultTypes当gen_server进程接收到使用cast / 2或者abcast / 2,3发送的请求时,这个函数被调用处理请求。有关参数和可能的返回值的说明,请参阅Module:handle_call / 3.Module:handle_info(Info,State) - > ResultTypesNoteThis回调是可选的,因此回调模块不需要导出它。 gen_server模块提供了该函数的默认实现,它记录了意外的Info消息,并将其丢弃并返回{noreply,State}。当发生超时或接收到任何其他消息时,由gen_server进程调用此函数同步或异步请求(或系统消息).Info可能是原子超时,发生超时或接收到的消息。有关其他参数和可能的返回值的说明,请参阅Module:handle_call / 3 .Module:init(Args) - > ResultTypes每当gen_server进程启动时使用start / 3,4或start_link / 3,4,这个函数被新进程调用来初始化.Args是提供给start函数的Args参数。如果初始化成功,则函数返回{ok,State},{ok,State,Timeout}或{ok,State,hibernate},其中State是gen_server进程的内部状态。如果整数时间 - 提供超时值,除非请求或消息发生超时在超时毫秒内收到。超时由原子超时值表示,该值由Module:handle_info / 2回调函数处理。原子无穷可以用来无限等待,这是默认值。如果指定hibernate而不是超时值,则在等待下一条消息到达时(通过调用proc_lib:hibernate / 3),进程进入休眠状态: 。如果初始化失败,函数将返回{stop,Reason},其中Reason是任意项,或ignore.Module:terminate(Reason,State)TypesNote此回调是可选的,因此回调模块不需要导出它。 gen_server模块提供了一个没有清理的默认实现。当gen_server模块即将终止时,该模块被gen_server进程调用。这与Module / init / 1相反,并且需要进行任何必要的清理。当它返回时,gen_server进程终止于Reason。返回值被忽略。原因是一个表示停止原因的术语,State是gen_server进程的内部状态。原因取决于gen_server进程终止的原因。如果是因为另一个回调函数返回了一个停止元组{stop,..},则Reason具有在该元组中指定的值。如果是因为失败,则Reason为错误原因。如果gen_server进程是监督树的一部分,并且由它的主管命令终止,则在下列条件适用的情况下使用Reason = shutdown调用此函数:
- 该
gen_server
过程已被设置为陷阱出口信号。
- 监督员的子规范中定义的关闭策略是整数超时值,而不是
brutal_kill
。
即使gen_server
进程不是
监督树的一部分,如果它'EXIT'
从父进程收到消息,该函数也会被调用。Reason
与'EXIT'
消息中的相同。
否则,gen_server
进程立即终止。
请注意,比任何其他原因normal
,shutdown
或者{shutdown,Term}
,在gen_server
假设过程,因为一个错误和错误报告使用发出的终止error_logger:format/2
。
另见
gen_event(3)
,gen_statem(3)
,proc_lib(3)
,supervisor(3)
,sys(3)