summaryrefslogtreecommitdiff
path: root/docs/tutorials/007/page05.html
blob: a5ad7a8d62e51d24627abd6280f5b563a86b14d0 (plain)
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
<HTML>
<HEAD>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
   <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]">
   <META NAME="Author" CONTENT="James CE Johnson">
   <META NAME="Description" CONTENT="A first step towards using ACE productively">
   <TITLE>ACE Tutorial 007</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">

<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER>

<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER>


<P>
<HR WIDTH="100%">

<P>As you might expect, <A HREF="client_handler.h">client_handler.h</A>
is next.

<P>
<HR WIDTH="100%">
<BR>&nbsp;
<BR><FONT FACE="Arial,Helvetica">// $Id: client_handler.h,v 1.1 1998/08/30
23:47:14 schmidt Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">#ifndef CLIENT_HANDLER_H</FONT>
<BR><FONT FACE="Arial,Helvetica">#define CLIENT_HANDLER_H</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">/*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Our client handler must exist
somewhere in the ACE_Event_Handler object</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; hierarchy.&nbsp; This is
a requirement of the ACE_Reactor because it maintains</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; ACE_Event_Handler pointers
for each registered event handler.&nbsp; You could</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; derive our Client_Handler
directly from ACE_Event_Handler but you still have</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; to have an ACE_SOCK_Stream
for the actually connection.&nbsp; With a direct</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; derivative of ACE_Event_Handler,
you'll have to contain and maintain an</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; ACE_SOCK_Stream instance
yourself.&nbsp; With ACE_Svc_Handler (which is a</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; derivative of ACE_Event_Handler)
some of those details are handled for you.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">#include "ace/Svc_Handler.h"</FONT>
<BR><FONT FACE="Arial,Helvetica">#include "ace/SOCK_Stream.h"</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">class Client_Acceptor;</FONT>
<BR><FONT FACE="Arial,Helvetica">class Thread_Pool;</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">/*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Another feature of ACE_Svc_Handler
is it's ability to present the ACE_Task&lt;></FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; interface as well.&nbsp;
That's what the ACE_NULL_SYNCH parameter below is all</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; about.&nbsp; That's beyond
our scope here but we'll come back to it in the next</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; tutorial when we start looking
at concurrency options.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
<BR><FONT FACE="Arial,Helvetica">class Client_Handler : public ACE_Svc_Handler
&lt; ACE_SOCK_STREAM, ACE_NULL_SYNCH ></FONT>
<BR><FONT FACE="Arial,Helvetica">{</FONT>
<BR><FONT FACE="Arial,Helvetica">public:</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; typedef ACE_Svc_Handler &lt; ACE_SOCK_STREAM,
ACE_NULL_SYNCH > inherited;</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; // Constructor...</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; Client_Handler (void);</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; The destroy()
method is our preferred method of destruction.&nbsp; We could</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; have overloaded
the delete operator but that is neither easy nor</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; intuitive (at
least to me).&nbsp; Instead, we provide a new method of</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; destruction and
we make our destructor protected so that only ourselves,</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; our derivatives
and our friends can delete us. It's a nice</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; compromise.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; void destroy (void);</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Most ACE objects
have an open() method.&nbsp; That's how you make them ready</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; to do work.&nbsp;
ACE_Event_Handler has a virtual open() method which allows us</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; to create this
overrride.&nbsp; ACE_Acceptor&lt;> will invoke this method after</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; creating a new
Client_Handler when a client connects. Notice that the</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; parameter to
open() is a void*.&nbsp; It just so happens that the pointer</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; points to the
acceptor which created us.&nbsp; You would like for the parameter</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; to be an ACE_Acceptor&lt;>*
but since ACE_Event_Handler is generic, that</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; would tie it
too closely to the ACE_Acceptor&lt;> set of objects.&nbsp; In our</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; definition of
open() you'll see how we get around that.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; int open (void *_acceptor);</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; When an ACE_Task&lt;>
object falls out of the svc() method, the framework</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; will call the
close() method.&nbsp; That's where we want to cleanup ourselves</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; if we're running
in either thread-per-connection or thread-pool mode.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; int close(u_long flags = 0);</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; When there is
activity on a registered handler, the handle_input() method</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; of the handler
will be invoked.&nbsp; If that method returns an error code (eg</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; -- -1) then the
reactor will invoke handle_close() to allow the object to</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; clean itself
up. Since an event handler can be registered for more than</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; one type of callback,
the callback mask is provided to inform</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; handle_close()
exactly which method failed.&nbsp; That way, you don't have to</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; maintain state
information between your handle_* method calls. The _handle</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; parameter is
explained below...</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; int handle_close (ACE_HANDLE _handle,
ACE_Reactor_Mask _mask);</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; When we register
with the reactor, we're going to tell it that we want to</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; be notified of
READ events.&nbsp; When the reactor sees that there is read</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; activity for
us, our handle_input() will be invoked. The _handleg</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; provided is the
handle (file descriptor in Unix) of the actual connection</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; causing the activity.&nbsp;
Since we're derived from ACE_Svc_Handler&lt;> and it</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; maintains it's
own peer (ACE_SOCK_Stream) object, this is redundant for</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; us.&nbsp; However,
if we had been derived directly from ACE_Event_Handler, we</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; may have chosen
not to contain the peer.&nbsp; In that case, the _handleg</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; would be important
to us for reading the client's data.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; int handle_input (ACE_HANDLE _handle);</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">protected:</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; If the Client_Acceptor
which created us has chosen a thread-per-connection</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; strategy then
our open() method will activate us into a dedicate thread.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; The svc() method
will then execute in that thread performing some of the</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; functions we
used to leave up to the reactor.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; int svc(void);</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; This has nothing
at all to do with ACE.&nbsp; I've added this here as a worker</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; function which
I will call from handle_input().&nbsp; That allows me to</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; introduce concurrencly
in later tutorials with a no changes to the worker</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; function.&nbsp;
You can think of process() as application-level code and</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; everything elase
as application-framework code.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; int process (char *_rdbuf, int
_rdbuf_len);</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; We don't really
do anything in our destructor but we've declared it to be</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; protected to
prevent casual deletion of this object.&nbsp; As I said above, I</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; really would
prefer that everyone goes through the destroy() method to get</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; rid of us.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; ~Client_Handler (void);</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; When we
get to the definition of Client_Handler we'll see that there are</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
several places where we go back to the Client_Acceptor for information.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
It is generally a good idea to do that through an accesor rather than</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
using the member variable directly.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Client_Acceptor * client_acceptor(
void )</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{ return this->client_acceptor_; }</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; And since
you shouldn't access a member variable directly, neither should you</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
set (mutate) it.&nbsp; Although it might seem silly to do it this way,
you'll thank</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
yourself for it later.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; void client_acceptor( Client_Acceptor
* _client_acceptor )</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{ this->client_acceptor_ = _client_acceptor; }</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The concurrency()
accessor tells us the current concurrency strategy.&nbsp; It actually</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
queries the Client_Acceptor for it but by having the accessor in place,
we could</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
change our implementation without affecting everything that needs to know.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; int concurrency(void);</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Likewise
for access to the Thread_Pool that we belong to.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Thread_Pool * thread_pool(void);</FONT>
<BR><FONT FACE="Arial,Helvetica"></FONT>&nbsp;<FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Client_Acceptor * client_acceptor_;</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; For some
reason I didn't create accessor/mutator methods for this.&nbsp; So much
for</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
consistency....</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
This variable is used to remember the thread in which we were created:&nbsp;
the "creator"</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
thread in other words.&nbsp; handle_input() needs to know if it is operating
in the</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
main reactor thread (which is the one that created us) or if it is operating
in</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
one of the thread pool threads.&nbsp; More on this when we get to handle_input().</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; ACE_thread_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
creator_;</FONT>
<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">#endif // CLIENT_HANDLER_H</FONT>

<P>
<HR WIDTH="100%">

<P>Still, we're just not seeing a lot of changes due to intruduction of
the thread pool.&nbsp; That's a good thing! You don't want to go turning
your application upside down just because you changed thread models.

<P>
<HR WIDTH="100%">
<CENTER>[<A HREF="..">Tutorial
Index</A>] [<A HREF="page06.html">Continue
This Tutorial</A>]</CENTER>

</BODY>
</HTML>