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
|
<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>
<HR>
<P>Let's see what things we've had to add to <A HREF="client_acceptor.h">client_acceptor.h</A>.
<P>
<HR WIDTH="100%">
<PRE>
<font color=red>// $Id$</font>
<font color=blue>#ifndef</font> <font color=purple>CLIENT_ACCEPTOR_H</font>
<font color=blue>#define</font> <font color=purple>CLIENT_ACCEPTOR_H</font>
<font color=red>/* The ACE_Acceptor<> template lives in the ace/Acceptor.h header
file. You'll find a very consitent naming convention between the
ACE objects and the headers where they can be found. In general,
the ACE object ACE_Foobar will be found in ace/Foobar.h. */</font>
<font color=blue>#include</font> "<font color=green>ace/Acceptor.h</font>"
<font color=blue>#if !defined</font> (<font color=purple>ACE_LACKS_PRAGMA_ONCE</font>)
# pragma once
<font color=blue>#endif</font> <font color=red>/* ACE_LACKS_PRAGMA_ONCE */</font>
<font color=red>/* Since we want to work with sockets, we'll need a SOCK_Acceptor to
allow the clients to connect to us. */</font>
<font color=blue>#include</font> "<font color=green>ace/SOCK_Acceptor.h</font>"
<font color=red>/* The Client_Handler object we develop will be used to handle clients
once they're connected. The ACE_Acceptor<> template's first
parameter requires such an object. In some cases, you can get by
with just a forward declaration on the class, in others you have to
have the whole thing. */</font>
<font color=blue>#include</font> "<font color=green>client_handler.h</font>"
<font color=red>/* Parameterize the ACE_Acceptor<> such that it will listen for socket
connection attempts and create Client_Handler objects when they
happen. In Tutorial 001, we wrote the basic acceptor logic on our
own before we realized that ACE_Acceptor<> was available. You'll
get spoiled using the ACE templates because they take away a lot of
the tedious details! */</font>
typedef ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR> Client_Acceptor_Base;
<font color=blue>#include</font> "<font color=green>thread_pool.h</font>"
<font color=red>/* This time we've added quite a bit more to our acceptor. In
addition to providing a choice of concurrency strategies, we also
maintain a Thread_Pool object in case that strategy is chosen. The
object still isn't very complex but it's come a long way from the
simple typedef we had in Tutorial 5.
Why keep the thread pool as a member? If we go back to the inetd
concept you'll recall that we need several acceptors to make that
work. We may have a situation in which our different client types
requre different resources. That is, we may need a large thread
pool for some client types and a smaller one for others. We could
share a pool but then the client types may have undesirable impact
on one another.
Just in case you do want to share a single thread pool, there is a
constructor below that will let you do that. */</font>
class Client_Acceptor : public Client_Acceptor_Base
{
public:
typedef Client_Acceptor_Base inherited;
<font color=red>/* Now that we have more than two strategies, we need more than a
boolean to tell us what we're using. A set of enums is a good
choice because it allows us to use named values. Another option
would be a set of static const integers. */</font>
enum concurrency_t
{
single_threaded_,
thread_per_connection_,
thread_pool_
};
<font color=red>/* The default constructor allows the programmer to choose the
concurrency strategy. Since we want to focus on thread-pool,
that's what we'll use if nothing is specified. */</font>
Client_Acceptor (int concurrency = thread_pool_);
<font color=red>/* Another option is to construct the object with an existing thread
pool. The concurrency strategy is pretty obvious at that point. */</font>
Client_Acceptor (Thread_Pool &thread_pool);
<font color=red>/* Our destructor will take care of shutting down the thread-pool if
applicable. */</font>
~Client_Acceptor (void);
<font color=red>/* Open ourselves and register with the given reactor. The thread
pool size can be specified here if you want to use that
concurrency strategy. */</font>
int open (const ACE_INET_Addr &addr,
ACE_Reactor *reactor,
int pool_size = <font color=#008888>Thread_Pool::default_pool_size_</font>);
<font color=red>/* Close ourselves and our thread pool if applicable */</font>
int close (void);
<font color=red>/* What is our concurrency strategy? */</font>
int concurrency (void)
{
return this->concurrency_;
}
<font color=red>/* Give back a pointer to our thread pool. Our Client_Handler
objects will need this so that their handle_input() methods can
put themselves into the pool. Another alternative would be a
globally accessible thread pool. ACE_Singleton<> is a way to
achieve that. */</font>
Thread_Pool *thread_pool (void)
{
return &this->the_thread_pool_;
}
<font color=red>/* Since we can be constructed with a Thread_Pool reference, there
are times when we need to know if the thread pool we're using is
ours or if we're just borrowing it from somebody else. */</font>
int thread_pool_is_private (void)
{
return &the_thread_pool_ == &private_thread_pool_;
}
protected:
int concurrency_;
Thread_Pool private_thread_pool_;
Thread_Pool &the_thread_pool_;
};
<font color=blue>#endif</font> <font color=red>/* CLIENT_ACCEPTOR_H */</font>
</PRE>
<HR WIDTH="100%">
<P>Well, except for the new Thread_Pool member variable, most of the changes
are informational.
<P><HR WIDTH="100%">
<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page04.html">Continue This Tutorial</A>]</CENTER>
|