File: gen_server.html

package info (click to toggle)
erlang-doc-html 1%3A11.b.2-1
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 23,284 kB
  • ctags: 10,724
  • sloc: erlang: 505; ansic: 323; makefile: 62; perl: 61; sh: 45
file content (298 lines) | stat: -rw-r--r-- 9,413 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<!-- This document was generated using DocBuilder 3.3.3 -->
<HTML>
<HEAD>
  <TITLE>Gen_Server Behaviour</TITLE>
  <SCRIPT type="text/javascript" src="../../doc/erlresolvelinks.js">
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#FF00FF"
      ALINK="#FF0000">
<CENTER>
<A HREF="http://www.erlang.se"><IMG BORDER=0 ALT="[Ericsson AB]" SRC="min_head.gif"></A>
</CENTER>
<A NAME="2"><!-- Empty --></A>
<H2>2 Gen_Server Behaviour</H2>
<A NAME="gen_server"><!-- Empty --></A>
<P>This chapter should be read in conjunction with
<CODE>gen_server(3)</CODE>, where all interface functions and callback
functions are described in detail.<A NAME="2.1"><!-- Empty --></A>
<H3>2.1 Client-Server Principles</H3>

<P>The client-server model is characterized by a central server
and an arbitrary number of clients. The client-server model is
generally used for resource management operations, where several
different clients want to share a common resource. The server is
responsible for managing this resource.
<P>
<CENTER>
<IMG ALT="clientserver" SRC="clientserver.gif"><BR>
<EM><A NAME="clientserver"><!-- Empty --></A>Client-Server Model
</EM>

</CENTER>
<A NAME="2.2"><!-- Empty --></A>
<H3>2.2 Example</H3>

<P>An example of a simple server written in plain Erlang was
given in <A HREF="des_princ.html#ch1">Overview</A>.
The server can be re-implemented using <CODE>gen_server</CODE>,
resulting in this callback module:<A NAME="ex"><!-- Empty --></A>
<PRE>
-module(ch3).
-behaviour(gen_server).

-export([start_link/0]).
-export([alloc/0, free/1]).
-export([init/1, handle_call/3, handle_cast/2]).

start_link() -&#62;
    gen_server:start_link({local, ch3}, ch3, [], []).

alloc() -&#62;
    gen_server:call(ch3, alloc).

free(Ch) -&#62;
    gen_server:cast(ch3, {free, Ch}).

init(_Args) -&#62;
    {ok, channels()}.

handle_call(alloc, _From, Chs) -&#62;
    {Ch, Chs2} = alloc(Chs),
    {reply, Ch, Chs2}.

handle_cast({free, Ch}, Chs) -&#62;
    Chs2 = free(Ch, Chs),
    {noreply, Chs2}.
    
</PRE>

<P>The code is explained in the next sections.<A NAME="2.3"><!-- Empty --></A>
<H3>2.3 Starting a Gen_Server</H3>

<P>In the example in the previous section, the gen_server is started
by calling <CODE>ch3:start_link()</CODE>:
<PRE>
start_link() -&#62;
    gen_server:start_link({local, ch3}, ch3, [], []) =&#62; {ok, Pid}
    
</PRE>

<P><CODE>start_link</CODE> calls the function
<CODE>gen_server:start_link/4</CODE>. This function spawns and links to
a new process, a gen_server.
<P>
<UL>

<LI>
        The first argument <CODE>{local, ch3}</CODE> specifies the name. In
         this case, the gen_server will be locally registered as
         <CODE>ch3</CODE>.<BR>


        If the name is omitted, the gen_server is not registered.
         Instead its pid must be used. The name could also be given
         as <CODE>{global, Name}</CODE>, in which case the gen_server is
         registered using <CODE>global:register_name/2</CODE>.<BR>


</LI>


<LI>
        The second argument, <CODE>ch3</CODE>, is the name of the callback
         module, that is the module where the callback functions are
         located.<BR>


        In this case, the interface functions (<CODE>start_link</CODE>,
         <CODE>alloc</CODE> and <CODE>free</CODE>) are located in the same module
         as the callback functions (<CODE>init</CODE>, <CODE>handle_call</CODE> and
         <CODE>handle_cast</CODE>). This is normally good programming
         practice, to have the code corresponding to one process
         contained in one module.<BR>


</LI>


<LI>
        The third argument, [], is a term which is passed as-is to
         the callback function <CODE>init</CODE>. Here, <CODE>init</CODE> does not
         need any indata and ignores the argument.<BR>


</LI>


<LI>
        The fourth argument, [], is a list of options. See
         <CODE>gen_server(3)</CODE> for available options.<BR>


</LI>


</UL>

<P>If name registration succeeds, the new gen_server process calls
the callback function <CODE>ch3:init([])</CODE>. <CODE>init</CODE> is expected
to return <CODE>{ok, State}</CODE>, where <CODE>State</CODE> is the internal
state of the gen_server. In this case, the state is the available
channels.
<PRE>
init(_Args) -&#62;
    {ok, channels()}.
    
</PRE>

<P>Note that <CODE>gen_server:start_link</CODE> is synchronous. It does
not return until the gen_server has been initialized and is ready
to receive requests.
<P><CODE>gen_server:start_link</CODE> must be used if the gen_server is
part of a supervision tree, i.e. is started by a supervisor.
There is another function <CODE>gen_server:start</CODE> to start a
stand-alone gen_server, i.e. a gen_server which is not part of a
supervision tree.<A NAME="2.4"><!-- Empty --></A>
<H3>2.4 Synchronous Requests - Call</H3>

<P>The synchronous request <CODE>alloc()</CODE> is implemented using
<CODE>gen_server:call/2</CODE>:
<PRE>
alloc() -&#62;
    gen_server:call(ch3, alloc).
    
</PRE>

<P><CODE>ch3</CODE> is the name of the gen_server and must agree with
the name used to start it. <CODE>alloc</CODE> is the actual request.
<P>The request is made into a message and sent to the gen_server.
When the request is received, the gen_server calls
<CODE>handle_call(Request, From, State)</CODE> which is expected to
return a tuple <CODE>{reply, Reply, State1}</CODE>. <CODE>Reply</CODE> is
the reply which should be sent back to the client, and
<CODE>State1</CODE> is a new value for the state of the gen_server.
<PRE>
handle_call(alloc, _From, Chs) -&#62;
    {Ch, Chs2} = alloc(Chs),
    {reply, Ch, Chs2}.
    
</PRE>

<P>In this case, the reply is the allocated channel <CODE>Ch</CODE> and
the new state is the set of remaining available channels
<CODE>Chs2</CODE>.
<P>Thus, the call <CODE>ch3:alloc()</CODE> returns the allocated channel
<CODE>Ch</CODE> and the gen_server then waits for new requests, now
with an updated list of available channels.<A NAME="2.5"><!-- Empty --></A>
<H3>2.5 Asynchronous Requests - Cast</H3>

<P>The asynchronous request <CODE>free(Ch)</CODE> is implemented using
<CODE>gen_server:cast/2</CODE>:
<PRE>
free(Ch) -&#62;
    gen_server:cast(ch3, {free, Ch}).
    
</PRE>

<P><CODE>ch3</CODE> is the name of the gen_server. <CODE>{free, Ch}</CODE> is
the actual request.
<P>The request is made into a message and sent to the gen_server.
<CODE>cast</CODE>, and thus <CODE>free</CODE>, then returns <CODE>ok</CODE>.
<P>When the request is received, the gen_server calls
<CODE>handle_cast(Request, State)</CODE> which is expected to
return a tuple <CODE>{noreply, State1}</CODE>. <CODE>State1</CODE> is a new
value for the state of the gen_server.
<PRE>
handle_call({free, Ch}, Chs) -&#62;
    Chs2 = free(Ch, Chs),
    {noreply, Chs2}.
    
</PRE>

<P>In this case, the new state is the updated list of available
channels <CODE>Chs2</CODE>. The gen_server is now ready for new
requests.<A NAME="2.6"><!-- Empty --></A>
<H3>2.6 Stopping</H3>
<A NAME="2.6.1"><!-- Empty --></A>
<H4>2.6.1 In a Supervision Tree</H4>

<P>If the gen_server is part of a supervision tree, no stop
        function is needed. The gen_server will automatically be
        terminated by its supervisor. Exactly how this is done is
        defined by a <A HREF="sup_princ.html#shutdown">shutdown
         strategy</A> set in the supervisor.
<P>If it is necessary to clean up before termination, the shutdown
        strategy must be a timeout value and the gen_server must be set
        to trap exit signals in the <CODE>init</CODE> function. When ordered
        to shutdown, the gen_server will then call the callback function
        <CODE>terminate(shutdown, State)</CODE>:
<PRE>
init(Args) -&#62;
    ...,
    process_flag(trap_exit, true),
    ...,
    {ok, State}.

...

terminate(shutdown, State) -&#62;
    ..code for cleaning up here..
    ok.
      
</PRE>
<A NAME="2.6.2"><!-- Empty --></A>
<H4>2.6.2 Stand-Alone Gen_Servers</H4>

<P>If the gen_server is not part of a supervision tree, a stop
        function may be useful, for example:
<PRE>
...
export([stop/0]).
...

stop() -&#62;
    gen_server:cast(ch3, stop).
...

handle_cast(stop, State) -&#62;
    {stop, normal, State};
handle_cast({free, Ch}, State) -&#62;
    ....

...

terminate(normal, State) -&#62;
    ok.
      
</PRE>

<P>The callback function handling the <CODE>stop</CODE> request returns
        a tuple <CODE>{stop, normal, State1}</CODE>, where <CODE>normal</CODE>
        specifies that it is a normal termination and <CODE>State1</CODE> is
        a new value for the state of the gen_server. This will cause
        the gen_server to call <CODE>terminate(normal,State1)</CODE> and then
        terminate gracefully.<A NAME="2.7"><!-- Empty --></A>
<H3>2.7 Handling Other Messages</H3>

<P>If the gen_server should be able to receive other messages than
requests, the callback function <CODE>handle_info(Info, State)</CODE>
must be implemented to handle them. Examples of other messages
are exit messages, if the gen_server is linked to other processes
(than the supervisor) and trapping exit signals.
<PRE>
handle_info({'EXIT', Pid, Reason}, State) -&#62;
    ..code to handle exits here..
    {noreply, State1}.
    
</PRE>
<CENTER>
<HR>
<SMALL>
Copyright &copy; 1991-2006
<A HREF="http://www.erlang.se">Ericsson AB</A><BR>
</SMALL>
</CENTER>
</BODY>
</HTML>