summaryrefslogtreecommitdiff
path: root/docs/tutorials/007
diff options
context:
space:
mode:
authorjcej <jcej@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1999-01-21 21:02:56 +0000
committerjcej <jcej@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1999-01-21 21:02:56 +0000
commit082060f4adf0a32c14b3296e7de1dc8b2f48214c (patch)
treeb2a910a16159afd9c72957cdae9159a126e222b1 /docs/tutorials/007
parent636792d3a13806de99344a764eced7a1cbe63a6d (diff)
downloadATCD-082060f4adf0a32c14b3296e7de1dc8b2f48214c.tar.gz
*** empty log message ***
Diffstat (limited to 'docs/tutorials/007')
-rw-r--r--docs/tutorials/007/Makefile12
-rw-r--r--docs/tutorials/007/combine.shar676
-rw-r--r--docs/tutorials/007/page01.html64
-rw-r--r--docs/tutorials/007/page02.html301
-rw-r--r--docs/tutorials/007/page03.html386
-rw-r--r--docs/tutorials/007/page04.html181
-rw-r--r--docs/tutorials/007/page05.html118
-rw-r--r--docs/tutorials/007/page06.html162
-rw-r--r--docs/tutorials/007/page07.html279
-rw-r--r--docs/tutorials/007/page08.html800
-rw-r--r--docs/tutorials/007/page09.html16
-rw-r--r--docs/tutorials/007/thread_pool.cpp2
12 files changed, 1615 insertions, 1382 deletions
diff --git a/docs/tutorials/007/Makefile b/docs/tutorials/007/Makefile
index 8e430900570..f9599da7063 100644
--- a/docs/tutorials/007/Makefile
+++ b/docs/tutorials/007/Makefile
@@ -90,6 +90,18 @@ Depend : depend
.depend : #
touch .depend
+
+HTML : #
+ [ -f hdr ] || $(MAKE) UNSHAR
+ perl ../combine *.pre ; chmod +r *.html
+
+SHAR : #
+ [ ! -f combine.shar ] || exit 1
+ shar -T hdr bodies *.pre *.pst > combine.shar && rm -f hdr bodies *.pre *.pst
+
+UNSHAR : #
+ sh combine.shar
+
#----------------------------------------------------------------------------
# Dependencies
#----------------------------------------------------------------------------
diff --git a/docs/tutorials/007/combine.shar b/docs/tutorials/007/combine.shar
new file mode 100644
index 00000000000..e0a98ea39db
--- /dev/null
+++ b/docs/tutorials/007/combine.shar
@@ -0,0 +1,676 @@
+#!/bin/sh
+# This is a shell archive (produced by GNU sharutils 4.2).
+# To extract the files from this archive, save it to some FILE, remove
+# everything before the `!/bin/sh' line above, then type `sh FILE'.
+#
+# Made on 1999-01-21 15:59 EST by <jcej@beta.mobsec.com>.
+# Source directory was `/projects/home/jcej/projects/ACE_wrappers/docs/tutorials/007'.
+#
+# Existing files will *not* be overwritten unless `-c' is specified.
+#
+# This shar contains:
+# length mode name
+# ------ ---------- ------------------------------------------
+# 575 -rw-rw-r-- hdr
+# 123 -rw-rw-r-- bodies
+# 3153 -rw-rw-r-- page01.pre
+# 87 -rw-rw-r-- page02.pre
+# 120 -rw-rw-r-- page03.pre
+# 171 -rw-rw-r-- page04.pre
+# 105 -rw-rw-r-- page05.pre
+# 160 -rw-rw-r-- page06.pre
+# 340 -rw-rw-r-- page07.pre
+# 135 -rw-rw-r-- page08.pre
+# 2071 -rw-rw-r-- page09.pre
+# 173 -rw-rw-r-- page02.pst
+# 116 -rw-rw-r-- page03.pst
+# 106 -rw-rw-r-- page04.pst
+# 234 -rw-rw-r-- page05.pst
+# 177 -rw-rw-r-- page06.pst
+# 97 -rw-rw-r-- page07.pst
+#
+save_IFS="${IFS}"
+IFS="${IFS}:"
+gettext_dir=FAILED
+locale_dir=FAILED
+first_param="$1"
+for dir in $PATH
+do
+ if test "$gettext_dir" = FAILED && test -f $dir/gettext \
+ && ($dir/gettext --version >/dev/null 2>&1)
+ then
+ set `$dir/gettext --version 2>&1`
+ if test "$3" = GNU
+ then
+ gettext_dir=$dir
+ fi
+ fi
+ if test "$locale_dir" = FAILED && test -f $dir/shar \
+ && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
+ then
+ locale_dir=`$dir/shar --print-text-domain-dir`
+ fi
+done
+IFS="$save_IFS"
+if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
+then
+ echo=echo
+else
+ TEXTDOMAINDIR=$locale_dir
+ export TEXTDOMAINDIR
+ TEXTDOMAIN=sharutils
+ export TEXTDOMAIN
+ echo="$gettext_dir/gettext -s"
+fi
+touch -am 1231235999 $$.touch >/dev/null 2>&1
+if test ! -f 1231235999 && test -f $$.touch; then
+ shar_touch=touch
+else
+ shar_touch=:
+ echo
+ $echo 'WARNING: not restoring timestamps. Consider getting and'
+ $echo "installing GNU \`touch', distributed in GNU File Utilities..."
+ echo
+fi
+rm -f 1231235999 $$.touch
+#
+if mkdir _sh32671; then
+ $echo 'x -' 'creating lock directory'
+else
+ $echo 'failed to create lock directory'
+ exit 1
+fi
+# ============= hdr ==============
+if test -f 'hdr' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'hdr' '(file already exists)'
+else
+ $echo 'x -' extracting 'hdr' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'hdr' &&
+<HTML>
+<HEAD>
+X <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+X <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]">
+X <META NAME="Author" CONTENT="James CE Johnson">
+X <META NAME="Description" CONTENT="A first step towards using ACE productively">
+X <TITLE>ACE Tutorial 007</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+X
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER>
+X
+<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER>
+<HR>
+SHAR_EOF
+ $shar_touch -am 0121152699 'hdr' &&
+ chmod 0664 'hdr' ||
+ $echo 'restore of' 'hdr' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'hdr:' 'MD5 check failed'
+8c1e8f73c777567099ea4e11a860ea56 hdr
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'hdr'`"
+ test 575 -eq "$shar_count" ||
+ $echo 'hdr:' 'original size' '575,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= bodies ==============
+if test -f 'bodies' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'bodies' '(file already exists)'
+else
+ $echo 'x -' extracting 'bodies' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'bodies' &&
+PAGE=2
+server.cpp
+client_acceptor.h
+client_acceptor.cpp
+client_handler.h
+client_handler.cpp
+thread_pool.h
+thread_pool.cpp
+X
+SHAR_EOF
+ $shar_touch -am 0121152599 'bodies' &&
+ chmod 0664 'bodies' ||
+ $echo 'restore of' 'bodies' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'bodies:' 'MD5 check failed'
+7675a97fa145886f534c43a8e1a0e6d1 bodies
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'bodies'`"
+ test 123 -eq "$shar_count" ||
+ $echo 'bodies:' 'original size' '123,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= page01.pre ==============
+if test -f 'page01.pre' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page01.pre' '(file already exists)'
+else
+ $echo 'x -' extracting 'page01.pre' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page01.pre' &&
+X
+X
+X
+<P>In this tutorial, we're going to extend Tutorial 6 to add a third concurrency
+strategy:&nbsp; thread-pool.&nbsp; Like Tutorial 6 did to Tutorial 5, we're
+going to keep the existing strategies that we've already created and add
+this one in as a "bonus".&nbsp; As you'll see, our basic objects will change
+but not by a whole lot.&nbsp; To accomplish this, we'll introduce one new
+major object that helps to abstract the thread pool concept.
+<P>
+Some folks have noted that this tutorial is a bit confusing if you
+don't first know about ACE_Task. My advice is to give it all a good
+read a couple of times. If you're still having problems, take a look
+at the ACE_Task tests in $ACE_ROOT/tests or examples in $ACE_ROOT/examples.
+<P>
+Kirthika's Abstract:
+<UL>
+In this multithreaded server, the Client_Acceptor has the additional
+strategy of managing a thread pool. This helps when two clients don't
+want to share the same resources or when different clients
+need to run in different priority threads. We could then pool all the
+same priority clients into one thread-pool. The thread_pool class is a
+new addition used to implement this strategy. It inherits from ACE_Task
+with ACE_MT_SYNCH parameter which takes care of syncronization issues
+amongst multiple threads.
+<P>
+ACE_Task follows the Active Object pattern and executes the methods on
+the task object in a new thread of execution, i.e it decouples the
+execution of a method from its invocation. An ACE_Task has an underlying
+thread (or pool of threads) and a Message_Queue which is the only means
+of communication among tasks. A Message_Queue consists of
+Message_Blocks.
+<P>
+The Client_Acceptor is registered with the reactor waiting for
+connection requests.
+On some activity, the reactor calls the handle_input() method on the
+Acceptor. The Client_Handler of the Acceptor (for the thread-pool
+strategy) unregisters itself from the reactor and
+enqueues itself in the Message_Queue of the thread-pool waiting for
+svc() to call handle_input() on it. It would then process the data in
+its new thread of execution. The ACE_MT_SYNCH option facilitates access
+of the Mesage_Blocks across different Message_Queues (here from the main
+thread to the one in the thread pool).
+<P>
+The thread_pool class derives from the ACE_Task class. Its svc() method
+dequeues the threads in the Message_Queue and calls handle_input() on
+them. The idle threads can take work from the queue while the other
+threads are working. It also uses ACE_Atomic_Op as a counter for active
+threads in the pool. Also, the ACE_Guard class has been used to provide
+thread-safe counter-incrementation and destruction of the Message_Blocks
+of the thread-pool. This class guards the critical section region by
+acquiring the mutex lock on creation and releasing it as soon as it goes
+out of scope.
+<P>
+Note: a sleep period before all the threads in the pool exit is
+necessary for complete destruction of the thread pool.
+<P>
+This tutorial gives us a flavour of implementing a server with a
+thread-pool strategy and how it can be managed using the ACE_Task class,
+which provides an OO approach to thread-creation and implementation.
+</UL>
+SHAR_EOF
+ $shar_touch -am 0121153399 'page01.pre' &&
+ chmod 0664 'page01.pre' ||
+ $echo 'restore of' 'page01.pre' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page01.pre:' 'MD5 check failed'
+ec4906ec2d89c587a2f8b520fa2b6edb page01.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page01.pre'`"
+ test 3153 -eq "$shar_count" ||
+ $echo 'page01.pre:' 'original size' '3153,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= page02.pre ==============
+if test -f 'page02.pre' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page02.pre' '(file already exists)'
+else
+ $echo 'x -' extracting 'page02.pre' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page02.pre' &&
+<P>As usualy, we start with <A HREF="server.cpp">server.cpp</A>
+<BR>
+<HR WIDTH="100%">
+SHAR_EOF
+ $shar_touch -am 0121152699 'page02.pre' &&
+ chmod 0664 'page02.pre' ||
+ $echo 'restore of' 'page02.pre' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page02.pre:' 'MD5 check failed'
+37639524942e8882c94523e5189b22ff page02.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page02.pre'`"
+ test 87 -eq "$shar_count" ||
+ $echo 'page02.pre:' 'original size' '87,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= page03.pre ==============
+if test -f 'page03.pre' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page03.pre' '(file already exists)'
+else
+ $echo 'x -' extracting 'page03.pre' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page03.pre' &&
+X
+<P>Let's see what things we've had to add to <A HREF="client_acceptor.h">client_acceptor.h</A>.
+X
+<P>
+<HR WIDTH="100%">
+SHAR_EOF
+ $shar_touch -am 0121152699 'page03.pre' &&
+ chmod 0664 'page03.pre' ||
+ $echo 'restore of' 'page03.pre' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page03.pre:' 'MD5 check failed'
+64592ded5ea700b4147face8ad77018f page03.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page03.pre'`"
+ test 120 -eq "$shar_count" ||
+ $echo 'page03.pre:' 'original size' '120,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= page04.pre ==============
+if test -f 'page04.pre' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page04.pre' '(file already exists)'
+else
+ $echo 'x -' extracting 'page04.pre' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page04.pre' &&
+X
+<P>Something new this time is <A HREF="client_acceptor.cpp">client_acceptor.cpp</A>.&nbsp;
+I finally had enough code to move it out of the header.
+X
+<P>
+<HR WIDTH="100%">
+SHAR_EOF
+ $shar_touch -am 0121152699 'page04.pre' &&
+ chmod 0664 'page04.pre' ||
+ $echo 'restore of' 'page04.pre' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page04.pre:' 'MD5 check failed'
+d5640eb97c0a746761c946c4e93db2e8 page04.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pre'`"
+ test 171 -eq "$shar_count" ||
+ $echo 'page04.pre:' 'original size' '171,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= page05.pre ==============
+if test -f 'page05.pre' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page05.pre' '(file already exists)'
+else
+ $echo 'x -' extracting 'page05.pre' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page05.pre' &&
+X
+<P>As you might expect, <A HREF="client_handler.h">client_handler.h</A>
+is next.
+X
+<P>
+<HR WIDTH="100%">
+SHAR_EOF
+ $shar_touch -am 0121152699 'page05.pre' &&
+ chmod 0664 'page05.pre' ||
+ $echo 'restore of' 'page05.pre' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page05.pre:' 'MD5 check failed'
+e882d389de5d95571737cfc58552153a page05.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page05.pre'`"
+ test 105 -eq "$shar_count" ||
+ $echo 'page05.pre:' 'original size' '105,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= page06.pre ==============
+if test -f 'page06.pre' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page06.pre' '(file already exists)'
+else
+ $echo 'x -' extracting 'page06.pre' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page06.pre' &&
+X
+<P><A HREF="client_handler.cpp">client_handler.cpp</A>
+shows some of the changes due to the thread-pool.&nbsp;&nbsp; Just a few
+though.
+X
+<P>
+<HR WIDTH="100%">
+SHAR_EOF
+ $shar_touch -am 0121152699 'page06.pre' &&
+ chmod 0664 'page06.pre' ||
+ $echo 'restore of' 'page06.pre' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page06.pre:' 'MD5 check failed'
+d884389625246dfcd8049f0fc648997d page06.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page06.pre'`"
+ test 160 -eq "$shar_count" ||
+ $echo 'page06.pre:' 'original size' '160,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= page07.pre ==============
+if test -f 'page07.pre' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page07.pre' '(file already exists)'
+else
+ $echo 'x -' extracting 'page07.pre' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page07.pre' &&
+<P>Two new files this time.&nbsp; The first is <A HREF="thread_pool.h">thread_pool.h</A>
+where we declare our Thread_Pool object.&nbsp; This is responsible for
+abstracting away the thread pool implementation details and allowing us
+to make so few changes to the rest of the code.
+X
+<P>
+<HR WIDTH="100%"><FONT FACE="Arial,Helvetica"></FONT>
+X
+SHAR_EOF
+ $shar_touch -am 0121152699 'page07.pre' &&
+ chmod 0664 'page07.pre' ||
+ $echo 'restore of' 'page07.pre' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page07.pre:' 'MD5 check failed'
+e5bcf4bee3e756dda50ccb69c18ac3a1 page07.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page07.pre'`"
+ test 340 -eq "$shar_count" ||
+ $echo 'page07.pre:' 'original size' '340,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= page08.pre ==============
+if test -f 'page08.pre' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page08.pre' '(file already exists)'
+else
+ $echo 'x -' extracting 'page08.pre' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page08.pre' &&
+X
+<P>Finally, <A HREF="thread_pool.cpp">thread_pool.cpp</A>
+where we have the Thread_Pool object implementation.
+X
+<P>
+<HR WIDTH="100%">
+SHAR_EOF
+ $shar_touch -am 0121152699 'page08.pre' &&
+ chmod 0664 'page08.pre' ||
+ $echo 'restore of' 'page08.pre' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page08.pre:' 'MD5 check failed'
+f8912fa7d6f1140a741479243bf5e924 page08.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page08.pre'`"
+ test 135 -eq "$shar_count" ||
+ $echo 'page08.pre:' 'original size' '135,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= page09.pre ==============
+if test -f 'page09.pre' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page09.pre' '(file already exists)'
+else
+ $echo 'x -' extracting 'page09.pre' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page09.pre' &&
+X
+<P>That's it for Tutorial 7.&nbsp; As with Tutorial 6, we really didn't
+have to change much to introduce a new threading strategy.&nbsp; Most of
+the work was in creating the Thread_Pool object itself.&nbsp; Everything
+else was just minor housekeeping.
+X
+<P>There is a fourth common thread strategy:&nbsp; thread-per-request.&nbsp;
+It's not one of my favorites, so I wasn't planning to go into it.&nbsp;
+If you want to contribute a tutorial on that topic though, I'll be glad
+to include it here.
+X
+<P>For reference, here's the file list again:
+<UL>
+<LI>
+<A HREF="Makefile">Makefile</A></LI>
+X
+<LI>
+<A HREF="client_acceptor.h">client_acceptor.h</A></LI>
+X
+<LI>
+<A HREF="client_acceptor.cpp">client_acceptor.cpp</A></LI>
+X
+<LI>
+<A HREF="client_handler.cpp">client_handler.cpp</A></LI>
+X
+<LI>
+<A HREF="client_handler.h">client_handler.h</A></LI>
+X
+<LI>
+<A HREF="server.cpp">server.cpp</A></LI>
+X
+<LI>
+<A HREF="thread_pool.h">thread_pool.h</A></LI>
+X
+<LI>
+<A HREF="thread_pool.cpp">thread_pool.cpp</A></LI>
+X
+</UL>
+<P>
+<HR WIDTH="100%">
+<P>
+<center><h2>Danger, Warning!</h2></center>
+Now that I've gone through all of this to create a thread pool server,
+I have to point out that this isn't exactly the best or safest way to
+do so. The biggest danger we face with this approach is the
+possibility of an event handler existing in the thread pool's message
+queue <i>after</i> it has been deleted. When the thread's svc()
+method attempts to invoke <i>handle_input()</i> you will get a nasty
+core dump.
+<p>
+The safest way to handle the situation is to use reference-counted
+pointers everywhere a Client_Handler pointer would be used. That's
+beyond the scope of the tutorial but I encourage you to give it a
+try. If you want to contribute that back as an enhanced Tutorial,
+I'll be glad to include it.
+<p>
+Another approach that should work quite well is to use the
+ACE_TP_Reactor instead of just ACE_Reactor. This takes a little more
+setup but results in a cleaner implementation. Again, I've not had
+time to develop a Tutorial on the TP_Reactor but would welcome any
+contributions.
+SHAR_EOF
+ $shar_touch -am 0121152599 'page09.pre' &&
+ chmod 0664 'page09.pre' ||
+ $echo 'restore of' 'page09.pre' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page09.pre:' 'MD5 check failed'
+74f66ca26c13797dcf3f8c3132bfe580 page09.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page09.pre'`"
+ test 2071 -eq "$shar_count" ||
+ $echo 'page09.pre:' 'original size' '2071,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= page02.pst ==============
+if test -f 'page02.pst' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page02.pst' '(file already exists)'
+else
+ $echo 'x -' extracting 'page02.pst' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page02.pst' &&
+<HR WIDTH="100%">
+X
+<P>Hmmm... No change there.&nbsp;&nbsp; Maybe I should leave out comments
+on the stuff I don't change.&nbsp; Let's take a look at client_acceptor.h.
+X
+<P>
+SHAR_EOF
+ $shar_touch -am 0121152899 'page02.pst' &&
+ chmod 0664 'page02.pst' ||
+ $echo 'restore of' 'page02.pst' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page02.pst:' 'MD5 check failed'
+b6226123f4f50eeb16db2f7675aaa171 page02.pst
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page02.pst'`"
+ test 173 -eq "$shar_count" ||
+ $echo 'page02.pst:' 'original size' '173,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= page03.pst ==============
+if test -f 'page03.pst' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page03.pst' '(file already exists)'
+else
+ $echo 'x -' extracting 'page03.pst' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page03.pst' &&
+<HR WIDTH="100%">
+X
+<P>Well, except for the new Thread_Pool member variable, most of the changes
+are informational.
+X
+SHAR_EOF
+ $shar_touch -am 0121152699 'page03.pst' &&
+ chmod 0664 'page03.pst' ||
+ $echo 'restore of' 'page03.pst' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page03.pst:' 'MD5 check failed'
+88a4cc7d635a4a6b7645011be580808f page03.pst
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page03.pst'`"
+ test 116 -eq "$shar_count" ||
+ $echo 'page03.pst:' 'original size' '116,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= page04.pst ==============
+if test -f 'page04.pst' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page04.pst' '(file already exists)'
+else
+ $echo 'x -' extracting 'page04.pst' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page04.pst' &&
+<HR WIDTH="100%">
+X
+<P>Nothing really surprising here.&nbsp; Most of it just manages the Thread_Pool.
+X
+<P>
+SHAR_EOF
+ $shar_touch -am 0121152699 'page04.pst' &&
+ chmod 0664 'page04.pst' ||
+ $echo 'restore of' 'page04.pst' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page04.pst:' 'MD5 check failed'
+57acbd600df965b4dc96ef0ad7ea9390 page04.pst
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pst'`"
+ test 106 -eq "$shar_count" ||
+ $echo 'page04.pst:' 'original size' '106,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= page05.pst ==============
+if test -f 'page05.pst' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page05.pst' '(file already exists)'
+else
+ $echo 'x -' extracting 'page05.pst' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page05.pst' &&
+<HR WIDTH="100%">
+X
+<P>Still, we're just not seeing a lot of changes due to introduction 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.
+X
+SHAR_EOF
+ $shar_touch -am 0121152899 'page05.pst' &&
+ chmod 0664 'page05.pst' ||
+ $echo 'restore of' 'page05.pst' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page05.pst:' 'MD5 check failed'
+98cba63a4dffe925484ca86368c863bb page05.pst
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page05.pst'`"
+ test 234 -eq "$shar_count" ||
+ $echo 'page05.pst:' 'original size' '234,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= page06.pst ==============
+if test -f 'page06.pst' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page06.pst' '(file already exists)'
+else
+ $echo 'x -' extracting 'page06.pst' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page06.pst' &&
+<HR WIDTH="100%">
+X
+<P>Ok, now we've gone and changed handle_input() so that it knows when
+to do work and when to enqueue itself.&nbsp; Beyond that, we're still about
+the same.
+X
+SHAR_EOF
+ $shar_touch -am 0121152699 'page06.pst' &&
+ chmod 0664 'page06.pst' ||
+ $echo 'restore of' 'page06.pst' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page06.pst:' 'MD5 check failed'
+bfbc05b1679c397403e7106ef12065d9 page06.pst
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page06.pst'`"
+ test 177 -eq "$shar_count" ||
+ $echo 'page06.pst:' 'original size' '177,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= page07.pst ==============
+if test -f 'page07.pst' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page07.pst' '(file already exists)'
+else
+ $echo 'x -' extracting 'page07.pst' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page07.pst' &&
+<HR WIDTH="100%">
+X
+<P>Well, that doesn't look too complex.&nbsp; What about the implementation?
+X
+SHAR_EOF
+ $shar_touch -am 0121152699 'page07.pst' &&
+ chmod 0664 'page07.pst' ||
+ $echo 'restore of' 'page07.pst' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page07.pst:' 'MD5 check failed'
+c1a7fbfe20f12e5a8bdeccc7c8e1af1c page07.pst
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page07.pst'`"
+ test 97 -eq "$shar_count" ||
+ $echo 'page07.pst:' 'original size' '97,' 'current size' "$shar_count!"
+ fi
+fi
+rm -fr _sh32671
+exit 0
diff --git a/docs/tutorials/007/page01.html b/docs/tutorials/007/page01.html
index 24b94f686c7..c69d9678172 100644
--- a/docs/tutorials/007/page01.html
+++ b/docs/tutorials/007/page01.html
@@ -11,10 +11,9 @@
<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>
-<HR WIDTH="100%">
<P>In this tutorial, we're going to extend Tutorial 6 to add a third concurrency
strategy:&nbsp; thread-pool.&nbsp; Like Tutorial 6 did to Tutorial 5, we're
@@ -22,12 +21,57 @@ going to keep the existing strategies that we've already created and add
this one in as a "bonus".&nbsp; As you'll see, our basic objects will change
but not by a whole lot.&nbsp; To accomplish this, we'll introduce one new
major object that helps to abstract the thread pool concept.
-
<P>
-<HR WIDTH="100%">
-<CENTER>[<A HREF="..">Tutorial
-Index</A>] [<A HREF="page02.html">Continue
-This Tutorial</A>]</CENTER>
-
-</BODY>
-</HTML>
+Some folks have noted that this tutorial is a bit confusing if you
+don't first know about ACE_Task. My advice is to give it all a good
+read a couple of times. If you're still having problems, take a look
+at the ACE_Task tests in $ACE_ROOT/tests or examples in $ACE_ROOT/examples.
+<P>
+Kirthika's Abstract:
+<UL>
+In this multithreaded server, the Client_Acceptor has the additional
+strategy of managing a thread pool. This helps when two clients don't
+want to share the same resources or when different clients
+need to run in different priority threads. We could then pool all the
+same priority clients into one thread-pool. The thread_pool class is a
+new addition used to implement this strategy. It inherits from ACE_Task
+with ACE_MT_SYNCH parameter which takes care of syncronization issues
+amongst multiple threads.
+<P>
+ACE_Task follows the Active Object pattern and executes the methods on
+the task object in a new thread of execution, i.e it decouples the
+execution of a method from its invocation. An ACE_Task has an underlying
+thread (or pool of threads) and a Message_Queue which is the only means
+of communication among tasks. A Message_Queue consists of
+Message_Blocks.
+<P>
+The Client_Acceptor is registered with the reactor waiting for
+connection requests.
+On some activity, the reactor calls the handle_input() method on the
+Acceptor. The Client_Handler of the Acceptor (for the thread-pool
+strategy) unregisters itself from the reactor and
+enqueues itself in the Message_Queue of the thread-pool waiting for
+svc() to call handle_input() on it. It would then process the data in
+its new thread of execution. The ACE_MT_SYNCH option facilitates access
+of the Mesage_Blocks across different Message_Queues (here from the main
+thread to the one in the thread pool).
+<P>
+The thread_pool class derives from the ACE_Task class. Its svc() method
+dequeues the threads in the Message_Queue and calls handle_input() on
+them. The idle threads can take work from the queue while the other
+threads are working. It also uses ACE_Atomic_Op as a counter for active
+threads in the pool. Also, the ACE_Guard class has been used to provide
+thread-safe counter-incrementation and destruction of the Message_Blocks
+of the thread-pool. This class guards the critical section region by
+acquiring the mutex lock on creation and releasing it as soon as it goes
+out of scope.
+<P>
+Note: a sleep period before all the threads in the pool exit is
+necessary for complete destruction of the thread pool.
+<P>
+This tutorial gives us a flavour of implementing a server with a
+thread-pool strategy and how it can be managed using the ACE_Task class,
+which provides an OO approach to thread-creation and implementation.
+</UL>
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page02.html">Continue This Tutorial</A>]</CENTER>
diff --git a/docs/tutorials/007/page02.html b/docs/tutorials/007/page02.html
index c6e7bedec43..fabab39642d 100644
--- a/docs/tutorials/007/page02.html
+++ b/docs/tutorials/007/page02.html
@@ -11,187 +11,136 @@
<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%">
-
+<HR>
<P>As usualy, we start with <A HREF="server.cpp">server.cpp</A>
<BR>
<HR WIDTH="100%">
-
-<P><FONT FACE="Arial,Helvetica">// $Id: server.cpp,v 1.1 1998/08/30 16:04:12
-jcej Exp $</FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; We try to keep main() very
-simple.&nbsp; One of the ways we do that is to push</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; much of the complicated stuff
-into worker objects.&nbsp; In this case, we only</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; need to include the acceptor
-header in our main source file.&nbsp; We let it</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; worry about the "real work".</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-
-<P><FONT FACE="Arial,Helvetica">#include "client_acceptor.h"</FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; As before, we create a simple
-signal handler that will set our finished</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; flag.&nbsp; There are, of
-course, more elegant ways to handle program shutdown</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; requests but that isn't really
-our focus right now, so we'll just do the</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; easiest thing.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-
-<P><FONT FACE="Arial,Helvetica">static sig_atomic_t finished = 0;</FONT>
-<BR><FONT FACE="Arial,Helvetica">extern "C" void handler (int)</FONT>
-<BR><FONT FACE="Arial,Helvetica">{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp; finished = 1;</FONT>
-<BR><FONT FACE="Arial,Helvetica">}</FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; A server has to listen for
-clients at a known TCP/IP port.&nbsp; The default ACE</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; port is 10002 (at least on
-my system) and that's good enough for what&nbsp; we</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; want to do here.&nbsp; Obviously,
-a more robust application would take a command</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; line parameter or read from
-a configuration file or do some other&nbsp; clever</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; thing.&nbsp; Just like the
-signal handler above, though, that's what we want to</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; focus on, so we're taking
-the easy way out.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-
-<P><FONT FACE="Arial,Helvetica">static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Finally, we get to main.&nbsp;
-Some C++ compilers will complain loudly if your</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; function signature doesn't
-match the prototype.&nbsp; Even though we're not</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; going to use the parameters,
-we still&nbsp; have to specify them.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-
-<P><FONT FACE="Arial,Helvetica">int main (int argc, char *argv[])</FONT>
-<BR><FONT FACE="Arial,Helvetica">{</FONT>
-<BR><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; In our earlier servers, we
-used a global pointer to get to the reactor. I've</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; never really liked that idea,
-so I've moved it into main() this time. When</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; we&nbsp; get to the Client_Handler
-object you'll see how we manage to get a</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; pointer back to this reactor.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp; ACE_Reactor reactor;</FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; The acceptor
-will take care of letting clients connect to us.&nbsp; It will</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; also arrange
-for a&nbsp; Client_Handler to be created for each new client.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Since we're only
-going to listen at one&nbsp; TCP/IP port, we only need one</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; acceptor.&nbsp;
-If we wanted, though, we could create several of these&nbsp; and</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; listen at several
-ports.&nbsp; (That's what we would do if we wanted to rewrite</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; inetd for&nbsp;
-instance.)</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp; Client_Acceptor peer_acceptor;</FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Create an ACE_INET_Addr
-that represents our endpoint of a connection. We</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; then open our
-acceptor object with that Addr.&nbsp; Doing so tells the acceptor</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; where to listen
-for connections.&nbsp; Servers generally listen at "well known"</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; addresses.&nbsp;
-If not, there must be some mechanism by which the client is</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; informed of the
-server's address.</FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Note how ACE_ERROR_RETURN
-is used if we fail to open the acceptor.&nbsp; This</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; technique is
-used over and over again in our tutorials.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp; if (peer_acceptor.open (ACE_INET_Addr
-(PORT), &amp;reactor) == -1)</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; ACE_ERROR_RETURN ((LM_ERROR,
-"%p\n", "open"), -1);</FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Install our signal
-handler.&nbsp; You can actually register signal handlers</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; with the reactor.&nbsp;
-You might do that when the signal handler is</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; responsible for
-performing "real" work.&nbsp; Our simple flag-setter doesn't</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; justify deriving
-from ACE_Event_Handler and providing a callback function</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; though.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp; ACE_Sig_Action sa ((ACE_SignalHandler)
-handler, SIGINT);</FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Like ACE_ERROR_RETURN,
-the ACE_DEBUG macro gets used quite a bit.&nbsp; It's a</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; handy way to
-generate uniform debug output from your program.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp; ACE_DEBUG ((LM_DEBUG, "(%P|%t)
-starting up server daemon\n"));</FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; This will loop
-"forever" invoking the handle_events() method of our</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; reactor. handle_events()
-watches for activity on any registered handlers</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; and invokes their
-appropriate callbacks when necessary.&nbsp; Callback-driven</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; programming is
-a big thing in ACE, you should get used to it. If the</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; signal handler
-catches something, the finished flag will be set and we'll</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; exit.&nbsp; Conveniently
-enough, handle_events() is also interrupted by signals</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; and will exit
-back to the while() loop.&nbsp; (If you want your event loop to</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; not be interrupted
-by signals, checkout the &lt;i>restart&lt;/i> flag on the</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; open() method
-of ACE_Reactor if you're interested.)</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp; while (!finished)</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-reactor.handle_events ();</FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp; ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting
-down server daemon\n"));</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp; return 0;</FONT>
-<BR><FONT FACE="Arial,Helvetica">}</FONT>
-
-<P>
+<PRE>
+<font color=red>// $Id$</font>
+
+<font color=red>/*
+ We try to keep main() very simple. One of the ways we do that is to push
+ much of the complicated stuff into worker objects. In this case, we only
+ need to include the acceptor header in our main source file. We let it
+ worry about the "<font color=green>real work</font>".
+ */</font>
+
+<font color=blue>#include</font> "<font color=green>client_acceptor.h</font>"
+
+<font color=red>/*
+ As before, we create a simple signal handler that will set our finished
+ flag. There are, of course, more elegant ways to handle program shutdown
+ requests but that isn't really our focus right now, so we'll just do the
+ easiest thing.
+ */</font>
+
+static sig_atomic_t finished = 0;
+extern "<font color=green>C</font>" void handler (int)
+{
+ finished = 1;
+}
+
+<font color=red>/*
+ A server has to listen for clients at a known TCP/IP port. The default ACE
+ port is 10002 (at least on my system) and that's good enough for what we
+ want to do here. Obviously, a more robust application would take a command
+ line parameter or read from a configuration file or do some other clever
+ thing. Just like the signal handler above, though, that's what we want to
+ focus on, so we're taking the easy way out.
+ */</font>
+
+static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+<font color=red>/*
+ Finally, we get to main. Some C++ compilers will complain loudly if your
+ function signature doesn't match the prototype. Even though we're not
+ going to use the parameters, we still have to specify them.
+ */</font>
+
+int main (int argc, char *argv[])
+{
+<font color=red>/*
+ In our earlier servers, we used a global pointer to get to the reactor. I've
+ never really liked that idea, so I've moved it into main() this time. When
+ we get to the Client_Handler object you'll see how we manage to get a
+ pointer back to this reactor.
+ */</font>
+ ACE_Reactor reactor;
+
+ <font color=red>/*
+ The acceptor will take care of letting clients connect to us. It will
+ also arrange for a Client_Handler to be created for each new client.
+ Since we're only going to listen at one TCP/IP port, we only need one
+ acceptor. If we wanted, though, we could create several of these and
+ listen at several ports. (That's what we would do if we wanted to rewrite
+ inetd for instance.)
+ */</font>
+ Client_Acceptor peer_acceptor;
+
+ <font color=red>/*
+ Create an ACE_INET_Addr that represents our endpoint of a connection. We
+ then open our acceptor object with that Addr. Doing so tells the acceptor
+ where to listen for connections. Servers generally listen at "<font color=green>well known</font>"
+ addresses. If not, there must be some mechanism by which the client is
+ informed of the server's address.
+
+ Note how ACE_ERROR_RETURN is used if we fail to open the acceptor. This
+ technique is used over and over again in our tutorials.
+ */</font>
+ if (peer_acceptor.open (ACE_INET_Addr (PORT), &reactor) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green>open</font>"), -1);
+
+ <font color=red>/*
+ Install our signal handler. You can actually register signal handlers
+ with the reactor. You might do that when the signal handler is
+ responsible for performing "<font color=green>real</font>" work. Our simple flag-setter doesn't
+ justify deriving from ACE_Event_Handler and providing a callback function
+ though.
+ */</font>
+ ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+ <font color=red>/*
+ Like ACE_ERROR_RETURN, the ACE_DEBUG macro gets used quite a bit. It's a
+ handy way to generate uniform debug output from your program.
+ */</font>
+ ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) starting up server daemon\n</font>"));
+
+ <font color=red>/*
+ This will loop "<font color=green>forever</font>" invoking the handle_events() method of our
+ reactor. handle_events() watches for activity on any registered handlers
+ and invokes their appropriate callbacks when necessary. Callback-driven
+ programming is a big thing in ACE, you should get used to it. If the
+ signal handler catches something, the finished flag will be set and we'll
+ exit. Conveniently enough, handle_events() is also interrupted by signals
+ and will exit back to the while() loop. (If you want your event loop to
+ not be interrupted by signals, checkout the &lt;i>restart&lt;/i> flag on the
+ open() method of ACE_Reactor if you're interested.)
+ */</font>
+ while (!finished)
+ reactor.handle_events ();
+
+ ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) shutting down server daemon\n</font>"));
+
+ return 0;
+}
+
+<font color=blue>#if defined</font> (<font color=purple>ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION</font>)
+template class ACE_Acceptor &lt;Client_Handler, ACE_SOCK_ACCEPTOR>;
+template class ACE_Svc_Handler&lt;ACE_SOCK_STREAM, ACE_NULL_SYNCH>;
+template class ACE_Guard&lt;ACE_Mutex>;
+template class ACE_Atomic_Op&lt;ACE_Mutex, int>;
+<font color=blue>#elif defined</font> (<font color=purple>ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA</font>)
+<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Acceptor &lt;Client_Handler, ACE_SOCK_ACCEPTOR>
+<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Svc_Handler&lt;ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Guard&lt;ACE_Mutex>
+<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Atomic_Op&lt;ACE_Mutex, int>
+<font color=blue>#endif</font> <font color=red>/* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */</font>
+</PRE>
<HR WIDTH="100%">
<P>Hmmm... No change there.&nbsp;&nbsp; Maybe I should leave out comments
-on the stuff I don't change.&nbsp; Let's take a lookt at client_acceptor.h.
+on the stuff I don't change.&nbsp; Let's take a look at client_acceptor.h.
<P>
-<HR WIDTH="100%">
-<CENTER>[<A HREF="..">Tutorial
-Index</A>] [<A HREF="page03.html">Continue
-This Tutorial</A>]</CENTER>
-
-</BODY>
-</HTML>
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page03.html">Continue This Tutorial</A>]</CENTER>
diff --git a/docs/tutorials/007/page03.html b/docs/tutorials/007/page03.html
index af048108811..20ccb581c13 100644
--- a/docs/tutorials/007/page03.html
+++ b/docs/tutorials/007/page03.html
@@ -11,253 +11,159 @@
<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%">
+<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%">
-<BR><FONT FACE="Arial,Helvetica">// $Id: client_acceptor.h,v 1.1 1998/08/30
-16:04:11 jcej Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">#ifndef CLIENT_ACCEPTOR_H</FONT>
-<BR><FONT FACE="Arial,Helvetica">#define CLIENT_ACCEPTOR_H</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; The ACE_Acceptor&lt;> template
-lives in the ace/Acceptor.h header file. You'll</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; find a very consitent naming
-convention between the ACE objects and the</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; headers where they can be
-found.&nbsp; In general, the ACE object ACE_Foobar will</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; be found in ace/Foobar.h.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">#include "ace/Acceptor.h"</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Since we want to work with
-sockets, we'll need a SOCK_Acceptor to allow the</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; clients to connect to us.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">#include "ace/SOCK_Acceptor.h"</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; The Client_Handler object
-we develop will be used to handle clients once</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; they're connected.&nbsp;
-The ACE_Acceptor&lt;> template's first parameter requires</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; such an object.&nbsp; In
-some cases, you can get by with just a forward</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; declaration on the class,
-in others you have to have the whole thing.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">#include "client_handler.h"</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Parameterize the ACE_Acceptor&lt;>
-such that it will listen for socket</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; connection attempts and create
-Client_Handler objects when they happen. In</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Tutorial 001, we wrote the
-basic acceptor logic on our own before we</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; realized that ACE_Acceptor&lt;>
-was available.&nbsp; You'll get spoiled using the</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; ACE templates because they
-take away a lot of the tedious details!</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">typedef ACE_Acceptor &lt; Client_Handler,
-ACE_SOCK_ACCEPTOR > Client_Acceptor_Base;</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">#include "thread_pool.h"</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; This time we've added quite
-a bit more to our acceptor.&nbsp; In addition to</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; providing a choice of concurrency
-strategies, we also maintain a Thread_Pool</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; object in case that strategy
-is chosen.&nbsp; The object still isn't very complex</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; but it's come a long way
-from the simple typedef we had in Tutorial 5.</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Why keep the thread pool as
-a member?&nbsp; If we go back to the inetd concept</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; you'll recall that we need
-several acceptors to make that work.&nbsp; We may have</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; a situation in which our
-different client types requre different resources.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; That is, we may need a large
-thread pool for some client types and a smaller</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; one for others.&nbsp; We
-could share a pool but then the client types may have</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; undesirable impact on one
-another.</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Just in case you do want to
-share a single thread pool, there is a constructor</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; below that will let you do
-that.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">class Client_Acceptor : public Client_Acceptor_Base</FONT>
-<BR><FONT FACE="Arial,Helvetica">{</FONT>
-<BR><FONT FACE="Arial,Helvetica">public:</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-typedef Client_Acceptor_Base inherited;</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Now that we have more than two strategies, we need more than a boolean</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-to tell us what we're using.&nbsp; A set of enums is a good choice because</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-it allows us to use named values.&nbsp; Another option would be a set of</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-static const integers.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-enum concurrency_t</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-single_threaded_,</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-thread_per_connection_,</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-thread_pool_</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-};</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-The default constructor allows the programmer to choose the concurrency</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-strategy.&nbsp; Since we want to focus on thread-pool, that's what we'll
-use</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-if nothing is specified.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Client_Acceptor( int _concurrency = thread_pool_ );</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Another option is to construct the object with an existing thread pool.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-The&nbsp; concurrency strategy is pretty obvious at that point.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Client_Acceptor( Thread_Pool &amp; _thread_pool );</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Our destructor will take care of shutting down the thread-pool</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-if applicable.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-~Client_Acceptor( void );</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Open ourselves and register with the given reactor.&nbsp; The thread pool
-size</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-can be specified here if you want to use that concurrency strategy.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-int open( const ACE_INET_Addr &amp; _addr, ACE_Reactor * _reactor,</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-int _pool_size = Thread_Pool::default_pool_size_ );</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Close ourselves and our thread pool if applicable</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-int close(void);</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-What is our concurrency strategy?</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-int concurrency(void)</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-{ return this->concurrency_; }</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Give back a pointer to our thread pool.&nbsp; Our Client_Handler objects</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-will need this so that their handle_input() methods can put themselves</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-into the pool.&nbsp; Another alternative would be a globally accessible</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-thread pool.&nbsp; ACE_Singleton&lt;> is a way to achieve that.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Thread_Pool * thread_pool(void)</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-{ return &amp; this->the_thread_pool_; }</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Since we can be constructed with a Thread_Pool reference, there are times</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-when we need to know if the thread pool we're using is ours or if we're</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-just borrowing it from somebody else.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-int thread_pool_is_private(void)</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-{ return &amp;the_thread_pool_ == &amp;private_thread_pool_; }</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">protected:</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-int concurrency_;</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Thread_Pool&nbsp;&nbsp; private_thread_pool_;</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Thread_Pool &amp; the_thread_pool_;</FONT>
-<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">#endif // CLIENT_ACCEPTOR_H</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P>
+<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> "<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&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>
-
-</BODY>
-</HTML>
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page04.html">Continue This Tutorial</A>]</CENTER>
diff --git a/docs/tutorials/007/page04.html b/docs/tutorials/007/page04.html
index 34424605180..7a693d64a6f 100644
--- a/docs/tutorials/007/page04.html
+++ b/docs/tutorials/007/page04.html
@@ -11,123 +11,86 @@
<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%">
+<HR>
<P>Something new this time is <A HREF="client_acceptor.cpp">client_acceptor.cpp</A>.&nbsp;
I finally had enough code to move it out of the header.
<P>
<HR WIDTH="100%">
-<BR><FONT FACE="Arial,Helvetica">// $Id: client_acceptor.cpp,v 1.1 1998/08/30
-16:04:11 jcej Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">#include "client_acceptor.h"</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Construct ourselves with
-the chosen concurrency strategy.&nbsp; Notice that we also</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; set our Thread_Pool reference
-to our private instance.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">Client_Acceptor::Client_Acceptor( int
-_concurrency )</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;:&nbsp; concurrency_(_concurrency)</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; ,the_thread_pool_(private_thread_pool_)</FONT>
-<BR><FONT FACE="Arial,Helvetica">{</FONT>
-<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Construct ourselves with
-a reference to somebody else' Thread_Pool.&nbsp; Obvioulsy</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; our concurrency strategy
-is "thread_pool_" at this point.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">Client_Acceptor::Client_Acceptor( Thread_Pool
-&amp; _thread_pool )</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;:&nbsp; concurrency_(thread_pool_)</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; ,the_thread_pool_(_thread_pool)</FONT>
-<BR><FONT FACE="Arial,Helvetica">{</FONT>
-<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; When we're destructed, we
-may need to cleanup after ourselves.&nbsp; If we're running</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; with a thread pool that we
-own, it is up to us to close it down.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">Client_Acceptor::~Client_Acceptor( void
-)</FONT>
-<BR><FONT FACE="Arial,Helvetica">{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-if( this->concurrency() == thread_pool_ &amp;&amp; thread_pool_is_private()
-)</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-thread_pool()->close();</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-}</FONT>
-<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Similar to the destructor
-(and close() below) it is necessary for us to open the</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; thread pool in some circumstances.</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Notice how we delegate most
-of the open() work to the open() method of our baseclass.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">int Client_Acceptor::open( const ACE_INET_Addr
-&amp; _addr, ACE_Reactor * _reactor, int _pool_size )</FONT>
-<BR><FONT FACE="Arial,Helvetica">{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-if( this->concurrency() == thread_pool_ &amp;&amp; thread_pool_is_private()
-)</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-thread_pool()->open(_pool_size);</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-}</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-return inherited::open(_addr,_reactor);</FONT>
-<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Here again we find that we
-have to manage the thread pool.&nbsp; Like open() we also delegate</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; the other work to our baseclass.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">int Client_Acceptor::close(void)</FONT>
-<BR><FONT FACE="Arial,Helvetica">{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-if( this->concurrency() == thread_pool_ &amp;&amp; thread_pool_is_private()
-)</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-thread_pool()->close();</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-}</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-return inherited::close();</FONT>
-<BR><FONT FACE="Arial,Helvetica">}</FONT>
-<BR><FONT FACE="Arial,Helvetica"></FONT>&nbsp;<FONT FACE="Arial,Helvetica"></FONT>
-
-<P>
+<PRE>
+
+<font color=red>// $Id$</font>
+
+<font color=blue>#include</font> "<font color=green>client_acceptor.h</font>"
+
+<font color=red>/*
+ Construct ourselves with the chosen concurrency strategy. Notice that we also
+ set our Thread_Pool reference to our private instance.
+ */</font>
+<font color=#008888>Client_Acceptor::Client_Acceptor</font>( int _concurrency )
+ : concurrency_(_concurrency)
+ ,the_thread_pool_(private_thread_pool_)
+{
+}
+
+<font color=red>/*
+ Construct ourselves with a reference to somebody else' Thread_Pool. Obvioulsy
+ our concurrency strategy is "<font color=green>thread_pool_</font>" at this point.
+ */</font>
+<font color=#008888>Client_Acceptor::Client_Acceptor</font>( Thread_Pool & _thread_pool )
+ : concurrency_(thread_pool_)
+ ,the_thread_pool_(_thread_pool)
+{
+}
+
+<font color=red>/*
+ When we're destructed, we may need to cleanup after ourselves. If we're running
+ with a thread pool that we own, it is up to us to close it down.
+ */</font>
+<font color=#008888>Client_Acceptor::~Client_Acceptor</font>( void )
+{
+ if( this->concurrency() == thread_pool_ && thread_pool_is_private() )
+ {
+ thread_pool()->close();
+ }
+}
+
+<font color=red>/*
+ Similar to the destructor (and close() below) it is necessary for us to open the
+ thread pool in some circumstances.
+
+ Notice how we delegate most of the open() work to the open() method of our baseclass.
+ */</font>
+int <font color=#008888>Client_Acceptor::open</font>( const ACE_INET_Addr & _addr, ACE_Reactor * _reactor, int _pool_size )
+{
+ if( this->concurrency() == thread_pool_ && thread_pool_is_private() )
+ {
+ thread_pool()->open(_pool_size);
+ }
+
+ return <font color=#008888>inherited::open</font>(_addr,_reactor);
+}
+
+<font color=red>/*
+ Here again we find that we have to manage the thread pool. Like open() we also delegate
+ the other work to our baseclass.
+ */</font>
+int <font color=#008888>Client_Acceptor::close</font>(void)
+{
+ if( this->concurrency() == thread_pool_ && thread_pool_is_private() )
+ {
+ thread_pool()->close();
+ }
+
+ return <font color=#008888>inherited::close</font>();
+}
+
+</PRE>
<HR WIDTH="100%">
<P>Nothing really surprising here.&nbsp; Most of it just manages the Thread_Pool.
<P>
-<HR WIDTH="100%">
-<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page05.html">Continue
-This Tutorial</A>]</CENTER>
-
-</BODY>
-</HTML>
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page05.html">Continue This Tutorial</A>]</CENTER>
diff --git a/docs/tutorials/007/page05.html b/docs/tutorials/007/page05.html
index c797b188cec..f3b27749232 100644
--- a/docs/tutorials/007/page05.html
+++ b/docs/tutorials/007/page05.html
@@ -11,21 +11,21 @@
<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%">
+<HR>
<P>As you might expect, <A HREF="client_handler.h">client_handler.h</A>
is next.
<P>
<HR WIDTH="100%">
-<pre><FONT FACE="Arial,Helvetica">
-#ifndef CLIENT_HANDLER_H
-#define CLIENT_HANDLER_H
+<PRE>
+
+<font color=red>// $Id$</font>
-/*
+<font color=blue>#ifndef</font> <font color=purple>CLIENT_HANDLER_H</font>
+<font color=blue>#define</font> <font color=purple>CLIENT_HANDLER_H</font>
+
+<font color=red>/*
Our client handler must exist somewhere in the ACE_Event_Handler object
hierarchy. This is a requirement of the ACE_Reactor because it maintains
ACE_Event_Handler pointers for each registered event handler. You could
@@ -34,64 +34,64 @@ is next.
derivative of ACE_Event_Handler, you'll have to contain and maintain an
ACE_SOCK_Stream instance yourself. With ACE_Svc_Handler (which is a
derivative of ACE_Event_Handler) some of those details are handled for you.
- */
+ */</font>
-#include "ace/Svc_Handler.h"
+<font color=blue>#include</font> "<font color=green>ace/Svc_Handler.h</font>"
-#if !defined (ACE_LACKS_PRAGMA_ONCE)
+<font color=blue>#if !defined</font> (<font color=purple>ACE_LACKS_PRAGMA_ONCE</font>)
# pragma once
-#endif /* ACE_LACKS_PRAGMA_ONCE */
+<font color=blue>#endif</font> <font color=red>/* ACE_LACKS_PRAGMA_ONCE */</font>
-#include "ace/SOCK_Stream.h"
+<font color=blue>#include</font> "<font color=green>ace/SOCK_Stream.h</font>"
class Client_Acceptor;
class Thread_Pool;
-/*
- Another feature of ACE_Svc_Handler is it's ability to present the ACE_Task<>
+<font color=red>/*
+ Another feature of ACE_Svc_Handler is it's ability to present the ACE_Task&lt;>
interface as well. That's what the ACE_NULL_SYNCH parameter below is all
about. That's beyond our scope here but we'll come back to it in the next
tutorial when we start looking at concurrency options.
- */
-class Client_Handler : public ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH >
+ */</font>
+class Client_Handler : public ACE_Svc_Handler &lt; ACE_SOCK_STREAM, ACE_NULL_SYNCH >
{
public:
- typedef ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH > inherited;
+ typedef ACE_Svc_Handler &lt; ACE_SOCK_STREAM, ACE_NULL_SYNCH > inherited;
- // Constructor...
+ <font color=red>// Constructor...</font>
Client_Handler (void);
- /*
+ <font color=red>/*
The destroy() method is our preferred method of destruction. We could
have overloaded the delete operator but that is neither easy nor
intuitive (at least to me). Instead, we provide a new method of
destruction and we make our destructor protected so that only ourselves,
our derivatives and our friends can delete us. It's a nice
compromise.
- */
+ */</font>
void destroy (void);
- /*
+ <font color=red>/*
Most ACE objects have an open() method. That's how you make them ready
to do work. ACE_Event_Handler has a virtual open() method which allows us
- to create this overrride. ACE_Acceptor<> will invoke this method after
+ to create this overrride. ACE_Acceptor&lt;> will invoke this method after
creating a new Client_Handler when a client connects. Notice that the
parameter to open() is a void*. It just so happens that the pointer
points to the acceptor which created us. You would like for the parameter
- to be an ACE_Acceptor<>* but since ACE_Event_Handler is generic, that
- would tie it too closely to the ACE_Acceptor<> set of objects. In our
+ to be an ACE_Acceptor&lt;>* but since ACE_Event_Handler is generic, that
+ would tie it too closely to the ACE_Acceptor&lt;> set of objects. In our
definition of open() you'll see how we get around that.
- */
+ */</font>
int open (void *_acceptor);
- /*
- When an ACE_Task<> object falls out of the svc() method, the framework
+ <font color=red>/*
+ When an ACE_Task&lt;> object falls out of the svc() method, the framework
will call the close() method. That's where we want to cleanup ourselves
if we're running in either thread-per-connection or thread-pool mode.
- */
+ */</font>
int close(u_long flags = 0);
- /*
+ <font color=red>/*
When there is activity on a registered handler, the handle_input() method
of the handler will be invoked. If that method returns an error code (eg
-- -1) then the reactor will invoke handle_close() to allow the object to
@@ -103,106 +103,100 @@ public:
As a side-effect, the reactor will also invoke remove_handler()
for the object on the mask that caused the -1 return. This means
that we don't have to do that ourselves!
- */
+ */</font>
int handle_close (ACE_HANDLE _handle, ACE_Reactor_Mask _mask);
- /*
+ <font color=red>/*
When we register with the reactor, we're going to tell it that we want to
be notified of READ events. When the reactor sees that there is read
activity for us, our handle_input() will be invoked. The _handleg
provided is the handle (file descriptor in Unix) of the actual connection
- causing the activity. Since we're derived from ACE_Svc_Handler<> and it
+ causing the activity. Since we're derived from ACE_Svc_Handler&lt;> and it
maintains it's own peer (ACE_SOCK_Stream) object, this is redundant for
us. However, if we had been derived directly from ACE_Event_Handler, we
may have chosen not to contain the peer. In that case, the _handleg
would be important to us for reading the client's data.
- */
+ */</font>
int handle_input (ACE_HANDLE _handle);
protected:
- /*
+ <font color=red>/*
If the Client_Acceptor which created us has chosen a thread-per-connection
strategy then our open() method will activate us into a dedicate thread.
The svc() method will then execute in that thread performing some of the
functions we used to leave up to the reactor.
- */
+ */</font>
int svc(void);
- /*
+ <font color=red>/*
This has nothing at all to do with ACE. I've added this here as a worker
function which I will call from handle_input(). That allows me to
introduce concurrencly in later tutorials with a no changes to the worker
function. You can think of process() as application-level code and
everything elase as application-framework code.
- */
+ */</font>
int process (char *_rdbuf, int _rdbuf_len);
- /*
+ <font color=red>/*
We don't really do anything in our destructor but we've declared it to be
protected to prevent casual deletion of this object. As I said above, I
really would prefer that everyone goes through the destroy() method to get
rid of us.
- */
+ */</font>
~Client_Handler (void);
- /*
+ <font color=red>/*
When we get to the definition of Client_Handler we'll see that there are
several places where we go back to the Client_Acceptor for information.
It is generally a good idea to do that through an accesor rather than
using the member variable directly.
- */
+ */</font>
Client_Acceptor * client_acceptor( void )
{ return this->client_acceptor_; }
- /*
+ <font color=red>/*
And since you shouldn't access a member variable directly, neither should you
set (mutate) it. Although it might seem silly to do it this way, you'll thank
yourself for it later.
- */
+ */</font>
void client_acceptor( Client_Acceptor * _client_acceptor )
{ this->client_acceptor_ = _client_acceptor; }
- /*
+ <font color=red>/*
The concurrency() accessor tells us the current concurrency strategy. It actually
queries the Client_Acceptor for it but by having the accessor in place, we could
change our implementation without affecting everything that needs to know.
- */
+ */</font>
int concurrency(void);
- /*
+ <font color=red>/*
Likewise for access to the Thread_Pool that we belong to.
- */
+ */</font>
Thread_Pool * thread_pool(void);
Client_Acceptor * client_acceptor_;
- /*
+ <font color=red>/*
For some reason I didn't create accessor/mutator methods for this. So much for
consistency....
- This variable is used to remember the thread in which we were created: the "creator"
+ This variable is used to remember the thread in which we were created: the "<font color=green>creator</font>"
thread in other words. handle_input() needs to know if it is operating in the
main reactor thread (which is the one that created us) or if it is operating in
one of the thread pool threads. More on this when we get to handle_input().
- */
+ */</font>
ACE_thread_t creator_;
};
-#endif // CLIENT_HANDLER_H
-</pre>
+<font color=blue>#endif</font> <font color=red>// CLIENT_HANDLER_H</font>
+</PRE>
<HR WIDTH="100%">
-<P>Still, we're just not seeing a lot of changes due to intruduction of
+<P>Still, we're just not seeing a lot of changes due to introduction 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>
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page06.html">Continue This Tutorial</A>]</CENTER>
diff --git a/docs/tutorials/007/page06.html b/docs/tutorials/007/page06.html
index 3c2fdd30357..acfcb950bf1 100644
--- a/docs/tutorials/007/page06.html
+++ b/docs/tutorials/007/page06.html
@@ -11,10 +11,7 @@
<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%">
+<HR>
<P><A HREF="client_handler.cpp">client_handler.cpp</A>
shows some of the changes due to the thread-pool.&nbsp;&nbsp; Just a few
@@ -22,65 +19,68 @@ though.
<P>
<HR WIDTH="100%">
-<pre><FONT FACE="Arial,Helvetica">
-/*
+<PRE>
+
+<font color=red>// $Id$</font>
+
+<font color=red>/*
Since this is the third time we've seen most of this, I'm going to strip out almost
all of the comments that you've already seen. That way, you can concentrate on the
new items.
- */
+ */</font>
-#include "client_acceptor.h"
-#include "client_handler.h"
+<font color=blue>#include</font> "<font color=green>client_acceptor.h</font>"
+<font color=blue>#include</font> "<font color=green>client_handler.h</font>"
-/*
+<font color=red>/*
We're going to be registering and unregistering a couple of times. To make sure that
we use the same flags every time, I've created these handy macros.
- */
-#define REGISTER_MASK ACE_Event_Handler::READ_MASK
-#define REMOVE_MASK (ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL)
+ */</font>
+<font color=blue>#define</font> <font color=purple>REGISTER_MASK</font> <font color=#008888>ACE_Event_Handler::READ_MASK</font>
+<font color=blue>#define</font> <font color=purple>REMOVE_MASK</font> (<font color=#008888>ACE_Event_Handler::READ_MASK</font> | ACE_Event_Handler::DONT_CALL)
-/*
+<font color=red>/*
Our constructor still doesn't really do anything. We simply initialize the acceptor
- pointer to "null" and get our current thread id. The static self() method of ACE_Thread
+ pointer to "<font color=green>null</font>" and get our current thread id. The static self() method of ACE_Thread
will return you a thread id native to your platform.
- */
-Client_Handler::Client_Handler (void)
+ */</font>
+<font color=#008888>Client_Handler::Client_Handler</font> (void)
: client_acceptor_(0)
- ,creator_(ACE_Thread::self())
+ ,creator_(<font color=#008888>ACE_Thread::self</font>())
{
}
-Client_Handler::~Client_Handler (void)
+<font color=#008888>Client_Handler::~Client_Handler</font> (void)
{
this->peer().close();
}
-/*
+<font color=red>/*
Query our acceptor for the concurrency strategy. Notice that we don't bother
to check that our acceptor pointer is valid. That is proably a bad idea...
- */
-int Client_Handler::concurrency(void)
+ */</font>
+int <font color=#008888>Client_Handler::concurrency</font>(void)
{
return this->client_acceptor()->concurrency();
}
-/*
+<font color=red>/*
And here we ask the acceptor about the thread pool.
- */
-Thread_Pool * Client_Handler::thread_pool(void)
+ */</font>
+Thread_Pool * <font color=#008888>Client_Handler::thread_pool</font>(void)
{
return this->client_acceptor()->thread_pool();
}
-/*
+<font color=red>/*
Back to our open() method. This is straight out of Tutorial 6. There's
nothing additional here for the thread-pool implementation.
- */
-int Client_Handler::open (void *_acceptor)
+ */</font>
+int <font color=#008888>Client_Handler::open</font> (void *_acceptor)
{
client_acceptor( (Client_Acceptor *) _acceptor );
- if( concurrency() == Client_Acceptor::thread_per_connection_ )
+ if( concurrency() == <font color=#008888>Client_Acceptor::thread_per_connection_</font> )
{
return this->activate();
}
@@ -96,47 +96,51 @@ int Client_Handler::open (void *_acceptor)
if (this->reactor ()->register_handler (this, REGISTER_MASK) == -1)
{
- ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);
+ ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P|%t) can't register with reactor\n</font>"), -1);
}
- ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", addr.get_host_name ()));
+ ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) connected with %s\n</font>", addr.get_host_name ()));
return 0;
}
-/*
+<font color=red>/*
The destroy() method will remove us from the reactor (with the
DONT_CALL flag set!) and then free our memory. This allows us to
be closed from outside of the reactor context without any danger.
- */
-void Client_Handler::destroy (void)
+ */</font>
+void <font color=#008888>Client_Handler::destroy</font> (void)
{
this->reactor ()->remove_handler (this, REMOVE_MASK );
delete this;
}
-/*
+<font color=red>/*
As mentioned in the header, the typical way to close an object in a
- threaded context is to invoke it's close() method. We use the
- destroy() method to clean up after ourselves.
-*/
-int Client_Handler::close(u_long flags)
+ threaded context is to invoke it's close() method.
+*/</font>
+int <font color=#008888>Client_Handler::close</font>(u_long flags)
{
+ <font color=red>/*
+ We use the destroy() method to clean up after ourselves.
+ That will take care of removing us from the reactor and then
+ freeing our memory.
+ */</font>
this->destroy();
- /*
+ <font color=red>/*
Don't forward the close() to the baseclass! handle_close() above has
already taken care of delete'ing. Forwarding close() would cause that
to happen again and things would get really ugly at that point!
- */
+ */</font>
return 0;
}
-/*
+<font color=red>/*
We will be called when handle_input() returns -1. That's our queue
to delete ourselves to prevent memory leaks.
- */
-int Client_Handler::handle_close (ACE_HANDLE _handle, ACE_Reactor_Mask _mask)
+ */</font>
+int <font color=#008888>Client_Handler::handle_close</font> (ACE_HANDLE _handle, ACE_Reactor_Mask _mask)
{
ACE_UNUSED_ARG (_handle);
ACE_UNUSED_ARG (_mask);
@@ -146,7 +150,7 @@ int Client_Handler::handle_close (ACE_HANDLE _handle, ACE_Reactor_Mask _mask)
return 0;
}
-/*
+<font color=red>/*
In the open() method, we registered with the reactor and requested to be
notified when there is data to be read. When the reactor sees that activity
it will invoke this handle_input() method on us. As I mentioned, the _handle
@@ -159,50 +163,50 @@ int Client_Handler::handle_close (ACE_HANDLE _handle, ACE_Reactor_Mask _mask)
thread then we must be in the reactor. In that case, we arrange to be put
into the thread pool. If we're not in the creator thread then we must be
in the thread pool and we can do some work.
- */
-int Client_Handler::handle_input (ACE_HANDLE _handle)
+ */</font>
+int <font color=#008888>Client_Handler::handle_input</font> (ACE_HANDLE _handle)
{
ACE_UNUSED_ARG (_handle);
- /*
+ <font color=red>/*
Check our strategy. If we're using the thread pool and we're in the creation
thread then we know we were called by the reactor.
- */
- if( concurrency() == Client_Acceptor::thread_pool_ )
+ */</font>
+ if( concurrency() == <font color=#008888>Client_Acceptor::thread_pool_</font> )
{
- if( ACE_OS::thr_equal(ACE_Thread::self(),creator_) )
+ if( <font color=#008888>ACE_OS::thr_equal</font>(ACE_Thread::self(),creator_) )
{
- /*
+ <font color=red>/*
Remove ourselves from the reactor and ask to be put into the thread pool's
queue of work. (You should be able to use suspend_handler() but I've had
problems with that.)
- */
+ */</font>
this->reactor()->remove_handler( this, REMOVE_MASK );
return this->thread_pool()->enqueue(this);
}
}
- /*
+ <font color=red>/*
Any strategy other than thread-per-connection will eventually get here. If we're in the
single-threaded implementation or the thread-pool, we still have to pass this way.
- */
+ */</font>
char buf[128];
- ACE_OS::memset (buf, 0, sizeof (buf));
+ <font color=#008888>ACE_OS::memset</font> (buf, 0, sizeof (buf));
- /*
+ <font color=red>/*
Invoke the process() method to do the work but save it's return value instead
of returning it immediately.
- */
+ */</font>
int rval = this->process(buf,sizeof(buf));
- /*
+ <font color=red>/*
Now, we look again to see if we're in the thread-pool implementation. If so then we
need to re-register ourselves with the reactor so that we can get more work when it
is available. (If suspend_handler() worked then we would use resume_handler() here.)
- */
- if( concurrency() == Client_Acceptor::thread_pool_ )
+ */</font>
+ if( concurrency() == <font color=#008888>Client_Acceptor::thread_pool_</font> )
{
if( rval != -1 )
{
@@ -210,20 +214,20 @@ int Client_Handler::handle_input (ACE_HANDLE _handle)
}
}
- /*
+ <font color=red>/*
Return the result of process()
- */
+ */</font>
return(rval);
}
-/*
+<font color=red>/*
Remember that when we leave our svc() method, the framework will take care
of calling our close() method so that we can cleanup after ourselves.
- */
-int Client_Handler::svc(void)
+ */</font>
+int <font color=#008888>Client_Handler::svc</font>(void)
{
char buf[128];
- ACE_OS::memset (buf, 0, sizeof (buf));
+ <font color=#008888>ACE_OS::memset</font> (buf, 0, sizeof (buf));
while( 1 )
{
@@ -236,37 +240,31 @@ int Client_Handler::svc(void)
return(0);
}
-/*
+<font color=red>/*
Once again, we see that the application-level logic has not been at all affected
by our choice of threading models. Of course, I'm not sharing data between threads
or anything. We'll leave locking issues for a later tutorial.
- */
-int Client_Handler::process (char *_rdbuf, int _rdbuf_len)
+ */</font>
+int <font color=#008888>Client_Handler::process</font> (char *_rdbuf, int _rdbuf_len)
{
switch (this->peer ().recv (_rdbuf, _rdbuf_len))
{
case -1:
- ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client"), -1);
+ ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P|%t) %p bad read\n</font>", "<font color=green>client</font>"), -1);
case 0:
- ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing daemon (fd = %d)\n", this->get_handle ()), -1);
+ ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P|%t) closing daemon (fd = %d)\n</font>", this->get_handle ()), -1);
default:
- ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s", _rdbuf));
+ ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) from client: %s</font>", _rdbuf));
}
return 0;
}
-</pre>
+</PRE>
<HR WIDTH="100%">
<P>Ok, now we've gone and changed handle_input() so that it knows when
to do work and when to enqueue itself.&nbsp; Beyond that, we're still about
the same.
-<P>
-<HR WIDTH="100%">
-<CENTER>[<A HREF="..">Tutorial
-Index</A>] [<A HREF="page07.html">Continue
-This Tutorial</A>]</CENTER>
-
-</BODY>
-</HTML>
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page07.html">Continue This Tutorial</A>]</CENTER>
diff --git a/docs/tutorials/007/page07.html b/docs/tutorials/007/page07.html
index c4fd555cf68..d200d598791 100644
--- a/docs/tutorials/007/page07.html
+++ b/docs/tutorials/007/page07.html
@@ -11,11 +11,7 @@
<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%">
-
+<HR>
<P>Two new files this time.&nbsp; The first is <A HREF="thread_pool.h">thread_pool.h</A>
where we declare our Thread_Pool object.&nbsp; This is responsible for
abstracting away the thread pool implementation details and allowing us
@@ -24,174 +20,113 @@ to make so few changes to the rest of the code.
<P>
<HR WIDTH="100%"><FONT FACE="Arial,Helvetica"></FONT>
-<P><FONT FACE="Arial,Helvetica">// $Id: thread_pool.h,v 1.1 1998/08/30
-16:04:12 jcej Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">#ifndef THREAD_POOL_H</FONT>
-<BR><FONT FACE="Arial,Helvetica">#define THREAD_POOL_H</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; In order to implement a thread
-pool, we have to have an object that can create</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; a thread.&nbsp; The ACE_Task&lt;>
-is the basis for doing just such a thing.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">#include "ace/Task.h"</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; We need a forward reference
-for ACE_Event_Handler so that our enqueue() method</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; can accept a pointer to one.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">class ACE_Event_Handler;</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Although we modified the
-rest of our program to make use of the thread pool</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; implementation, if you look
-closely you'll see that the changes were rather</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; minor.&nbsp; The "ACE way"
-is generally to create a helper object that abstracts</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; away the details not relevant
-to your application.&nbsp; That's what I'm trying</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; to do here by creating the
-Thread_Pool object.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">class Thread_Pool : public ACE_Task&lt;ACE_MT_SYNCH></FONT>
-<BR><FONT FACE="Arial,Helvetica">{</FONT>
-<BR><FONT FACE="Arial,Helvetica">public:</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Provide an enumeration for the default pool size.&nbsp; By doing this,
-other objects</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-can use the value when they want a default.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-enum size_t</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-default_pool_size_ = 5</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-};</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-// Basic constructor</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Thread_Pool(void);</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Opening the thread pool causes one or more threads to be activated.&nbsp;
-When activated,</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-they all execute the svc() method declared below.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-int open( int _pool_size = default_pool_size_ );</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-When you're done wit the thread pool, you have to have some way to shut
-it down.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-This is what close() is for.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-int close(void);</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-To use the thread pool, you have to put some unit of work into it.&nbsp;
-Since we're</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-dealing with event handlers (or at least their derivatives), I've chosen
-to provide</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-an enqueue() method that takes a pointer to an ACE_Event_Handler.&nbsp;
-The handler's</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-handle_input() method will be called, so your object has to know when it
-is being</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-called by the thread pool.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-int enqueue( ACE_Event_Handler * _handler );</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">protected:</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Our svc() method will dequeue the enqueued event handler objects and invoke
-the</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-handle_input() method on each.&nbsp; Since we're likely running in more
-than one thread,</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-idle threads can take work from the queue while other threads are busy
-executing</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-handle_input() on some object.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-int svc(void);</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Another handy ACE template is ACE_Atomic_Op&lt;>.&nbsp; When parameterized,
-this allows</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-is to have a thread-safe counting object.&nbsp; The typical arithmetic
-operators are</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-all internally thread-safe so that you can share it across threads without
-worrying</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-about any contention issues.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-typedef ACE_Atomic_Op&lt;ACE_Mutex,int> counter_t;</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-We use the atomic op to keep a count of the number of threads in which
-our svc()</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-method is running.&nbsp; This is particularly important when we want to
-close() it down!</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-counter_t active_threads_;</FONT>
-<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">#endif // THREAD_POOL_H</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P>
+<PRE>
+
+<font color=red>// $Id$</font>
+
+<font color=blue>#ifndef</font> <font color=purple>THREAD_POOL_H</font>
+<font color=blue>#define</font> <font color=purple>THREAD_POOL_H</font>
+
+<font color=red>/*
+ In order to implement a thread pool, we have to have an object that can create
+ a thread. The ACE_Task&lt;> is the basis for doing just such a thing.
+ */</font>
+<font color=blue>#include</font> "<font color=green>ace/Task.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>/*
+ We need a forward reference for ACE_Event_Handler so that our enqueue() method
+ can accept a pointer to one.
+ */</font>
+class ACE_Event_Handler;
+
+<font color=red>/*
+ Although we modified the rest of our program to make use of the thread pool
+ implementation, if you look closely you'll see that the changes were rather
+ minor. The "<font color=green>ACE way</font>" is generally to create a helper object that abstracts
+ away the details not relevant to your application. That's what I'm trying
+ to do here by creating the Thread_Pool object.
+ */</font>
+class Thread_Pool : public ACE_Task&lt;ACE_MT_SYNCH>
+{
+public:
+
+ typedef ACE_Task&lt;ACE_MT_SYNCH> inherited;
+
+ <font color=red>/*
+ Provide an enumeration for the default pool size. By doing this, other objects
+ can use the value when they want a default.
+ */</font>
+ enum size_t
+ {
+ default_pool_size_ = 5
+ };
+
+ <font color=red>// Basic constructor</font>
+ Thread_Pool(void);
+
+ <font color=red>/*
+ Opening the thread pool causes one or more threads to be activated. When activated,
+ they all execute the svc() method declared below.
+ */</font>
+ int open( int _pool_size = default_pool_size_ );
+
+ <font color=red>/*
+ Some compilers will complain that our open() above attempts to
+ override a virtual function in the baseclass. We have no
+ intention of overriding that method but in order to keep the
+ compiler quiet we have to add this method as a pass-thru to the
+ baseclass method.
+ */</font>
+ virtual int open(void * _void_data)
+ { return <font color=#008888>inherited::open</font>(_void_data); }
+
+ <font color=red>/*
+ */</font>
+ int close( u_long flags = 0 );
+
+ <font color=red>/*
+ To use the thread pool, you have to put some unit of work into it. Since we're
+ dealing with event handlers (or at least their derivatives), I've chosen to provide
+ an enqueue() method that takes a pointer to an ACE_Event_Handler. The handler's
+ handle_input() method will be called, so your object has to know when it is being
+ called by the thread pool.
+ */</font>
+ int enqueue( ACE_Event_Handler * _handler );
+
+ <font color=red>/*
+ Another handy ACE template is ACE_Atomic_Op&lt;>. When parameterized, this allows
+ is to have a thread-safe counting object. The typical arithmetic operators are
+ all internally thread-safe so that you can share it across threads without worrying
+ about any contention issues.
+ */</font>
+ typedef ACE_Atomic_Op&lt;ACE_Mutex,int> counter_t;
+
+protected:
+
+ <font color=red>/*
+ Our svc() method will dequeue the enqueued event handler objects and invoke the
+ handle_input() method on each. Since we're likely running in more than one thread,
+ idle threads can take work from the queue while other threads are busy executing
+ handle_input() on some object.
+ */</font>
+ int svc(void);
+
+ <font color=red>/*
+ We use the atomic op to keep a count of the number of threads in which our svc()
+ method is running. This is particularly important when we want to close() it down!
+ */</font>
+ counter_t active_threads_;
+};
+
+<font color=blue>#endif</font> <font color=red>// THREAD_POOL_H</font>
+</PRE>
<HR WIDTH="100%">
<P>Well, that doesn't look too complex.&nbsp; What about the implementation?
-<P>
-<HR WIDTH="100%">
-<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page08.html">Continue
-This Tutorial</A>]</CENTER>
-
-</BODY>
-</HTML>
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page08.html">Continue This Tutorial</A>]</CENTER>
diff --git a/docs/tutorials/007/page08.html b/docs/tutorials/007/page08.html
index 094804e743d..5563fdb252f 100644
--- a/docs/tutorials/007/page08.html
+++ b/docs/tutorials/007/page08.html
@@ -11,527 +11,291 @@
<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%">
+<HR>
<P>Finally, <A HREF="thread_pool.cpp">thread_pool.cpp</A>
where we have the Thread_Pool object implementation.
<P>
<HR WIDTH="100%">
-
-<P><FONT FACE="Arial,Helvetica">// $Id: thread_pool.cpp,v 1.1 1998/08/30
-23:47:15 schmidt Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">#include "thread_pool.h"</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; We need this header so that
-we can invoke handle_input() on the objects we dequeue.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">#include "ace/Event_Handler.h"</FONT>
-<BR><FONT FACE="Arial,Helvetica"></FONT>&nbsp;<FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; All we do here is initialize
-our active thread counter.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">Thread_Pool::Thread_Pool(void)</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;: active_threads_(0)</FONT>
-<BR><FONT FACE="Arial,Helvetica">{</FONT>
-<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Our open() method is a thin
-disguise around the ACE_Task&lt;> activate() method.&nbsp; By</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; hiding activate() in this
-way, the users of Thread_Pool don't have to worry about</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; the thread configuration
-flags.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">int Thread_Pool::open( int _pool_size
-)</FONT>
-<BR><FONT FACE="Arial,Helvetica">{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp; return this->activate(THR_NEW_LWP|THR_DETACHED,_pool_size);</FONT>
-<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Closing the thread pool can
-be a tricky exercise.&nbsp; I've decided to take an easy approach</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; and simply enqueue a secret
-message for each thread we have active.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">int Thread_Pool::close(void)</FONT>
-<BR><FONT FACE="Arial,Helvetica">{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Find out how many threads are currently active</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-int counter = active_threads_.value();</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-For each one of the active threads, enqueue a "null" event handler.&nbsp;
-Below, we'll</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-teach our svc() method that "null" means "shutdown".</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-while( counter-- )</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-this->enqueue( 0 );</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-}</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-As each svc() method exits, it will decrement the active thread counter.&nbsp;
-We just wait</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-here for it to reach zero.&nbsp; Since we don't know how long it will take,
-we sleep for</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-a quarter-second or so between tries.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-while( active_threads_.value() )</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-ACE_OS::sleep( ACE_Time_Value(0.25) );</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-}</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-return(0);</FONT>
-<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; When an object wants to do
-work in the pool, it should call the enqueue() method.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; We introduce the ACE_Message_Block
-here but, unfortunately, we seriously missuse it.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">int Thread_Pool::enqueue( ACE_Event_Handler
-* _handler )</FONT>
-<BR><FONT FACE="Arial,Helvetica">{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-An ACE_Message_Block is a chunk of data.&nbsp; You put them into an ACE_Message_Queue.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-ACE_Task&lt;> has an ACE_Message_Queue built in.&nbsp; In fact, the parameter
-to ACE_Task&lt;></FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-is passed directly to ACE_Message_Queue.&nbsp; If you look back at our
-header file you'll</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-see that we used ACE_MT_SYNCH as the parameter indicating that we want
-MultiThread</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Synch safety.&nbsp; This allows us to safely put ACE_Message_Block objects
-into the</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-message queue in one thread and take them out in another.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-An ACE_Message_Block wants to have char* data.&nbsp; We don't have that.&nbsp;
-We could</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-cast our ACE_Event_Handler* directly to a char* but I wanted to be more
-explicit.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Since casting pointers around is a dangerous thing, I've gone out of my
-way here</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-to be very clear about what we're doing.</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-First:&nbsp; Cast the handler pointer to a void pointer.&nbsp; You can't
-do any useful work</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-on a void pointer, so this is a clear message that we're making the</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-pointer unusable.</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Next:&nbsp;&nbsp; Cast the void pointer to a char pointer that the ACE_Message_Block
-will accept.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-void * v_data = (void*)_handler;</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-char * c_data = (char*)v_data;</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Construct a new ACE_Message_Block.&nbsp; For efficiency, you might want
-to preallocate a</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-stack of these and reuse them.&nbsp; For simplicity, I'll just create what
-I need as I need it.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-ACE_Message_Block * mb = new ACE_Message_Block( c_data );</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Our putq() method is a wrapper around one of the enqueue methods of the
-ACE_Message_Queue</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-that we own.&nbsp; Like all good methods, it returns -1 if it fails for
-some reason.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-if( this->putq(mb) == -1 )</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Another trait of the ACE_Message_Block objects is that they are reference
-counted.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Since they're designed to be passed around between various objects in several
-threads</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-we can't just delete them whenever we feel like it.&nbsp; The release()
-method is similar</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-to the destroy() method we've used elsewhere.&nbsp; It watches the reference
-count and will</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-delete the object when possible.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-mb->release();</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-return(-1);</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-}</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-return(0);</FONT>
-<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; The "guard" concept is very
-powerful and used throughout multi-threaded applications.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; A guard normally does some
-operation on an object at construction and the "opposite"</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; operation at destruction.&nbsp;
-For instance, when you guard a mutex (lock) object, the guard</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; will acquire the lock on
-construction and release it on destruction.&nbsp; In this way, your</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; method can simply let the
-guard go out of scope and know that the lock is released.</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Guards aren't only useful
-for locks however.&nbsp; In this application I've created two guard</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; objects for quite a different
-purpose.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; The Counter_Guard is constructed
-with a reference to the thread pool's active thread</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; counter.&nbsp; The guard
-increments the counter when it is created and decrements it at</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; destruction.&nbsp; By creating
-one of these in svc(), I know that the counter will be decremented</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; no matter how or where svc()
-returns.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">class Counter_Guard</FONT>
-<BR><FONT FACE="Arial,Helvetica">{</FONT>
-<BR><FONT FACE="Arial,Helvetica">public:</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Counter_Guard( Thread_Pool::counter_t &amp; _counter )</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-: counter_(_counter)</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-++counter_;</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-}</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-~Counter_Guard(void)</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
---counter_;</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-}</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">protected:</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Thread_Pool::counter_t &amp; counter_;</FONT>
-<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; My Message_Block_Guard is
-also a little non-traditional.&nbsp; It doesn't do anything in the</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; constructor but it's destructor
-ensures that the message block's release() method is called.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; This is a cheap way to prevent
-a memory leak if I need an additional exit point in svc().</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">class Message_Block_Guard</FONT>
-<BR><FONT FACE="Arial,Helvetica">{</FONT>
-<BR><FONT FACE="Arial,Helvetica">public:</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Message_Block_Guard( ACE_Message_Block * &amp; _mb )</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-: mb_(_mb)</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-}</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-~Message_Block_Guard( void )</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-mb_->release();</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-}</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">protected:</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-ACE_Message_Block * &amp; mb_;</FONT>
-<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Now we come to the svc()
-method.&nbsp; As I said, this is being executed in each thread of the</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Thread_Pool.&nbsp; Here,
-we pull messages off of our built-in ACE_Message_Queue and cause them</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; to do work.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">int Thread_Pool::svc(void)</FONT>
-<BR><FONT FACE="Arial,Helvetica">{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-The getq() method takes a reference to a pointer.&nbsp; So... we need a
-pointer to give it</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-a reference to.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-ACE_Message_Block * mb;</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Create the guard for our active thread counter object.&nbsp; No matter
-where we choose to</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-return() from svc(), we no know that the counter will be decremented.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Counter_Guard counter_guard(active_threads_);</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Get messages from the queue until we have a failure.&nbsp; There's no real
-good reason</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-for failure so if it happens, we leave immediately.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-while( this->getq(mb) != -1 )</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-A successful getq() will cause "mb" to point to a valid refernce-counted</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-ACE_Message_Block.&nbsp; We use our guard object here so that we're sure
-to call</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-the release() method of that message block and reduce it's reference count.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Once the count reaches zero, it will be deleted.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Message_Block_Guard message_block_guard(mb);</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-As noted before, the ACE_Message_Block stores it's data as a char*.&nbsp;
-We pull that</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-out here and later turn it into an ACE_Event_Handler*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-char * c_data = mb->base();</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-We've chosen to use a "null" value as an indication to leave.&nbsp; If
-the data we got</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-from the queue is not null then we have some work to do.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-if( c_data )</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Once again, we go to great lengths to emphasize the fact that we're casting
-pointers</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-around in rather impolite ways.&nbsp; We could have cast the char* directly
-to an</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-ACE_Event_Handler* but then folks might think that's an OK thing to do.</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-(Note:&nbsp; The correct way to use an ACE_Message_Block is to write data
-into it.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-What I should have done was create a message block big enough to hold an</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-event handler pointer and then written the pointer value into the block.&nbsp;
-When</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-we got here, I would have to read that data back into a pointer.&nbsp;
-While politically</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-correct, it is also a lot of work.&nbsp; If you're careful you can get
-away with casting</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-pointers around.)</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-void * v_data = (void*)c_data;</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-ACE_Event_Handler * handler = (ACE_Event_Handler*)v_data;</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Now that we finally have an event handler pointer, invoke it's handle_input()
-method.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Since we don't know it's handle, we just give it a default.&nbsp; That's
-OK because we</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-know that we're not using the handle in the method anyway.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-if( handler->handle_input(ACE_INVALID_HANDLE) == -1 )</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Tell the handler that it's time to go home.&nbsp; The "normal" method for
-shutting</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-down a handler whose handler failed is to invoke handle_close().&nbsp;
-This will</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-take care of cleaning it up for us.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Notice how we use the handler's get_handle() method to populate it's "handle"</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-parameter.&nbsp; Convenient isn't it?</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-handler->handle_close(handler->get_handle(),0);</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Also notice that we don't exit the svc() method here!&nbsp; The first time
-I did</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-this, I was exiting.&nbsp; After a few clients disconnect you have an empty</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-thread pool.&nbsp; Hard to do any more work after that...</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-}</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-}</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-else</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-{</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-/*</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-If we get here, we were given a message block with "null" data.&nbsp; That
-is our</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-signal to leave, so we return(0) to leave gracefully.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-*/</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-return(0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-// Ok, shutdown request</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-}</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-// message_block_guard goes out of scope here</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-// and releases the message_block instance.</FONT>
-<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-}</FONT><FONT FACE="Arial,Helvetica"></FONT>
-
-<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-return(0);</FONT>
-<BR><FONT FACE="Arial,Helvetica">}</FONT>
-
-<P>
-<HR WIDTH="100%">
-<CENTER>[<A HREF="..">Tutorial
-Index</A>] [<A HREF="page09.html">Continue
-This Tutorial</A>]</CENTER>
-
-</BODY>
-</HTML>
+<PRE>
+
+<font color=red>// $Id$</font>
+
+<font color=blue>#include</font> "<font color=green>thread_pool.h</font>"
+
+<font color=red>/*
+ We need this header so that we can invoke handle_input() on the objects we dequeue.
+ */</font>
+<font color=blue>#include</font> "<font color=green>ace/Event_Handler.h</font>"
+
+
+<font color=red>/*
+ All we do here is initialize our active thread counter.
+ */</font>
+<font color=#008888>Thread_Pool::Thread_Pool</font>(void)
+ : active_threads_(0)
+{
+}
+
+<font color=red>/*
+ Our open() method is a thin disguise around the ACE_Task&lt;> activate() method. By
+ hiding activate() in this way, the users of Thread_Pool don't have to worry about
+ the thread configuration flags.
+ */</font>
+int <font color=#008888>Thread_Pool::open</font>( int _pool_size )
+{
+ return this->activate(THR_NEW_LWP,_pool_size);
+}
+
+<font color=red>/*
+ Closing the thread pool can be a tricky exercise. I've decided to take an easy approach
+ and simply enqueue a secret message for each thread we have active.
+ */</font>
+int <font color=#008888>Thread_Pool::close</font>( u_long flags )
+{
+ ACE_UNUSED_ARG(flags);
+
+ <font color=red>/*
+ Find out how many threads are currently active
+ */</font>
+ int counter = active_threads_.value();
+
+ <font color=red>/*
+ For each one of the active threads, enqueue a "<font color=green>null</font>" event handler. Below, we'll
+ teach our svc() method that "<font color=green>null</font>" means "<font color=green>shutdown</font>".
+ */</font>
+ while( counter-- )
+ {
+ this->enqueue( 0 );
+ }
+
+ <font color=red>/*
+ As each svc() method exits, it will decrement the active thread counter. We just wait
+ here for it to reach zero. Since we don't know how long it will take, we sleep for
+ a quarter-second or so between tries.
+ */</font>
+ while( active_threads_.value() )
+ {
+ <font color=#008888>ACE_OS::sleep</font>( ACE_Time_Value(0.25) );
+ }
+
+ return(0);
+}
+
+<font color=red>/*
+ When an object wants to do work in the pool, it should call the enqueue() method.
+ We introduce the ACE_Message_Block here but, unfortunately, we seriously missuse it.
+ */</font>
+int <font color=#008888>Thread_Pool::enqueue</font>( ACE_Event_Handler * _handler )
+{
+ <font color=red>/*
+ An ACE_Message_Block is a chunk of data. You put them into an ACE_Message_Queue.
+ ACE_Task&lt;> has an ACE_Message_Queue built in. In fact, the parameter to ACE_Task&lt;>
+ is passed directly to ACE_Message_Queue. If you look back at our header file you'll
+ see that we used ACE_MT_SYNCH as the parameter indicating that we want MultiThread
+ Synch safety. This allows us to safely put ACE_Message_Block objects into the
+ message queue in one thread and take them out in another.
+ */</font>
+
+ <font color=red>/*
+ An ACE_Message_Block wants to have char* data. We don't have that. We could
+ cast our ACE_Event_Handler* directly to a char* but I wanted to be more explicit.
+ Since casting pointers around is a dangerous thing, I've gone out of my way here
+ to be very clear about what we're doing.
+
+ First: Cast the handler pointer to a void pointer. You can't do any useful work
+ on a void pointer, so this is a clear message that we're making the
+ pointer unusable.
+
+ Next: Cast the void pointer to a char pointer that the ACE_Message_Block will accept.
+ */</font>
+ void * v_data = (void*)_handler;
+ char * c_data = (char*)v_data;
+
+ <font color=red>/*
+ Construct a new ACE_Message_Block. For efficiency, you might want to preallocate a
+ stack of these and reuse them. For simplicity, I'll just create what I need as I need it.
+ */</font>
+ ACE_Message_Block * mb = new ACE_Message_Block( c_data );
+
+ <font color=red>/*
+ Our putq() method is a wrapper around one of the enqueue methods of the ACE_Message_Queue
+ that we own. Like all good methods, it returns -1 if it fails for some reason.
+ */</font>
+ if( this->putq(mb) == -1 )
+ {
+ <font color=red>/*
+ Another trait of the ACE_Message_Block objects is that they are reference counted.
+ Since they're designed to be passed around between various objects in several threads
+ we can't just delete them whenever we feel like it. The release() method is similar
+ to the destroy() method we've used elsewhere. It watches the reference count and will
+ delete the object when possible.
+ */</font>
+ mb->release();
+ return(-1);
+ }
+
+ return(0);
+}
+
+<font color=red>/*
+ The "<font color=green>guard</font>" concept is very powerful and used throughout multi-threaded applications.
+ A guard normally does some operation on an object at construction and the "<font color=green>opposite</font>"
+ operation at destruction. For instance, when you guard a mutex (lock) object, the guard
+ will acquire the lock on construction and release it on destruction. In this way, your
+ method can simply let the guard go out of scope and know that the lock is released.
+
+ Guards aren't only useful for locks however. In this application I've created two guard
+ objects for quite a different purpose.
+ */</font>
+
+<font color=red>/*
+ The Counter_Guard is constructed with a reference to the thread pool's active thread
+ counter. The guard increments the counter when it is created and decrements it at
+ destruction. By creating one of these in svc(), I know that the counter will be decremented
+ no matter how or where svc() returns.
+ */</font>
+class Counter_Guard
+{
+public:
+ Counter_Guard( <font color=#008888>Thread_Pool::counter_t</font> & _counter )
+ : counter_(_counter)
+ {
+ ++counter_;
+ }
+
+ ~Counter_Guard(void)
+ {
+ --counter_;
+ }
+
+protected:
+ <font color=#008888>Thread_Pool::counter_t</font> & counter_;
+};
+
+<font color=red>/*
+ My Message_Block_Guard is also a little non-traditional. It doesn't do anything in the
+ constructor but it's destructor ensures that the message block's release() method is called.
+ This is a cheap way to prevent a memory leak if I need an additional exit point in svc().
+ */</font>
+class Message_Block_Guard
+{
+public:
+ Message_Block_Guard( ACE_Message_Block * & _mb )
+ : mb_(_mb)
+ {
+ }
+
+ ~Message_Block_Guard( void )
+ {
+ mb_->release();
+ }
+
+protected:
+ ACE_Message_Block * & mb_;
+};
+
+<font color=red>/*
+ Now we come to the svc() method. As I said, this is being executed in each thread of the
+ Thread_Pool. Here, we pull messages off of our built-in ACE_Message_Queue and cause them
+ to do work.
+ */</font>
+int <font color=#008888>Thread_Pool::svc</font>(void)
+{
+ <font color=red>/*
+ The getq() method takes a reference to a pointer. So... we need a pointer to give it
+ a reference to.
+ */</font>
+ ACE_Message_Block * mb;
+
+ <font color=red>/*
+ Create the guard for our active thread counter object. No matter where we choose to
+ return() from svc(), we now know that the counter will be decremented.
+ */</font>
+ Counter_Guard counter_guard(active_threads_);
+
+ <font color=red>/*
+ Get messages from the queue until we have a failure. There's no real good reason
+ for failure so if it happens, we leave immediately.
+ */</font>
+ while( this->getq(mb) != -1 )
+ {
+ <font color=red>/*
+ A successful getq() will cause "<font color=green>mb</font>" to point to a valid refernce-counted
+ ACE_Message_Block. We use our guard object here so that we're sure to call
+ the release() method of that message block and reduce it's reference count.
+ Once the count reaches zero, it will be deleted.
+ */</font>
+ Message_Block_Guard message_block_guard(mb);
+
+ <font color=red>/*
+ As noted before, the ACE_Message_Block stores it's data as a char*. We pull that
+ out here and later turn it into an ACE_Event_Handler*
+ */</font>
+ char * c_data = mb->base();
+
+ <font color=red>/*
+ We've chosen to use a "<font color=green>null</font>" value as an indication to leave. If the data we got
+ from the queue is not null then we have some work to do.
+ */</font>
+ if( c_data )
+ {
+ <font color=red>/*
+ Once again, we go to great lengths to emphasize the fact that we're casting pointers
+ around in rather impolite ways. We could have cast the char* directly to an
+ ACE_Event_Handler* but then folks might think that's an OK thing to do.
+
+ (Note: The correct way to use an ACE_Message_Block is to write data into it.
+ What I should have done was create a message block big enough to hold an
+ event handler pointer and then written the pointer value into the block. When
+ we got here, I would have to read that data back into a pointer. While politically
+ correct, it is also a lot of work. If you're careful you can get away with casting
+ pointers around.)
+ */</font>
+ void * v_data = (void*)c_data;
+
+ ACE_Event_Handler * handler = (ACE_Event_Handler*)v_data;
+
+ <font color=red>/*
+ Now that we finally have an event handler pointer, invoke it's handle_input() method.
+ Since we don't know it's handle, we just give it a default. That's OK because we
+ know that we're not using the handle in the method anyway.
+ */</font>
+ if( handler->handle_input(ACE_INVALID_HANDLE) == -1 )
+ {
+ <font color=red>/*
+ Tell the handler that it's time to go home. The "<font color=green>normal</font>" method for shutting
+ down a handler whose handler failed is to invoke handle_close(). This will
+ take care of cleaning it up for us.
+ Notice how we use the handler's get_handle() method to populate it's "<font color=green>handle</font>"
+ parameter. Convenient isn't it?
+ */</font>
+ handler->handle_close(handler->get_handle(),0);
+
+ <font color=red>/*
+ Also notice that we don't exit the svc() method here! The first time I did
+ this, I was exiting. After a few clients disconnect you have an empty
+ thread pool. Hard to do any more work after that...
+ */</font>
+ }
+ }
+ else
+ {
+ <font color=red>/*
+ If we get here, we were given a message block with "<font color=green>null</font>" data. That is our
+ signal to leave, so we return(0) to leave gracefully.
+ */</font>
+ return(0); <font color=red>// Ok, shutdown request</font>
+ }
+
+ <font color=red>// message_block_guard goes out of scope here</font>
+ <font color=red>// and releases the message_block instance.</font>
+ }
+
+ return(0);
+}
+
+</PRE>
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page09.html">Continue This Tutorial</A>]</CENTER>
diff --git a/docs/tutorials/007/page09.html b/docs/tutorials/007/page09.html
index 00e9ff650b5..498f6c19ffd 100644
--- a/docs/tutorials/007/page09.html
+++ b/docs/tutorials/007/page09.html
@@ -4,15 +4,14 @@
<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 006</TITLE>
+ <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 WIDTH="100%">
+<HR>
<P>That's it for Tutorial 7.&nbsp; As with Tutorial 6, we really didn't
have to change much to introduce a new threading strategy.&nbsp; Most of
@@ -50,8 +49,6 @@ to include it here.
<LI>
<A HREF="thread_pool.cpp">thread_pool.cpp</A></LI>
-<LI>
-<A HREF="fix.Makefile">fix.Makefile</A></LI>
</UL>
<P>
<HR WIDTH="100%">
@@ -76,10 +73,5 @@ ACE_TP_Reactor instead of just ACE_Reactor. This takes a little more
setup but results in a cleaner implementation. Again, I've not had
time to develop a Tutorial on the TP_Reactor but would welcome any
contributions.
-<P>
-<HR WIDTH="100%">
-<CENTER>[<A HREF="..">Tutorial
-Index</A>]</CENTER>
-
-</BODY>
-</HTML>
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] </CENTER>
diff --git a/docs/tutorials/007/thread_pool.cpp b/docs/tutorials/007/thread_pool.cpp
index 852b51ef232..c70d0995f53 100644
--- a/docs/tutorials/007/thread_pool.cpp
+++ b/docs/tutorials/007/thread_pool.cpp
@@ -190,7 +190,7 @@ int Thread_Pool::svc(void)
/*
Create the guard for our active thread counter object. No matter where we choose to
- return() from svc(), we no know that the counter will be decremented.
+ return() from svc(), we now know that the counter will be decremented.
*/
Counter_Guard counter_guard(active_threads_);