summaryrefslogtreecommitdiff
path: root/docs/tutorials/007/page03.html
blob: 8f7a6e9bb98f6ffd505046274a43b1ce00432e3b (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
<!-- $Id$ -->
<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&lt;> 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> "<A HREF="../../../ace/Acceptor.h">ace/Acceptor.h</A>"

<font color=blue>#if !defined</font> (<font color=purple>ACE_LACKS_PRAGMA_ONCE</font>)
<font color=blue># pragma</font> <font color=purple>once</font>
<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> "<A HREF="../../../ace/SOCK_Acceptor.h">ace/SOCK_Acceptor.h</A>"

<font color=red>/* The Client_Handler object we develop will be used to handle clients
   once they're connected.  The ACE_Acceptor&lt;> 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&lt;> 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&lt;> was available.  You'll
   get spoiled using the ACE templates because they take away a lot of
   the tedious details!  */</font>
typedef ACE_Acceptor &lt;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&lt;> 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>