#!/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-09-21 22:49 EDT by . # Source directory was `/home/jcej/projects/ACE_wrappers/docs/tutorials/006'. # # Existing files will *not* be overwritten unless `-c' is specified. # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ # 605 -rw-rw-r-- hdr # 72 -rw-rw-r-- bodies # 1974 -rw-rw-r-- page01.pre # 252 -rw-rw-r-- page02.pre # 507 -rw-rw-r-- page03.pre # 227 -rw-rw-r-- page04.pre # 231 -rw-rw-r-- page05.pre # 697 -rw-rw-r-- page06.pre # 89 -rw-rw-r-- page02.pst # 168 -rw-rw-r-- page03.pst # 175 -rw-rw-r-- page04.pst # 1420 -rw-rw-r-- page05.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 _sh04795; 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' && X X X X X ACE Tutorial 006 X
ACE Tutorial 006
X
Creating a thread-per-connection server
X X


SHAR_EOF $shar_touch -am 0118202399 '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' 3289bf210fdf2f4b9d0a23b69c79a82f hdr SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'hdr'`" test 605 -eq "$shar_count" || $echo 'hdr:' 'original size' '605,' '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_handler.h client_handler.cpp SHAR_EOF $shar_touch -am 0118202399 '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' 1f7383474ecfc75883354e67afaf1b3b bodies SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'bodies'`" test 72 -eq "$shar_count" || $echo 'bodies:' 'original size' '72,' '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

In this tutorial, we're going to extend Tutorial 5 to create a thread-per-connection server.  This implementation will create a new thread for each client which connects to us.  The ACE_Reactor is still used but only for accepting new connections.  The Client_Handler objects won't be registered with the reactor.  Instead, they'll be responsible for monitoring their peer() directly.

Abstract:*

* Abstract by Kirthika as always SHAR_EOF $shar_touch -am 0118203099 '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' b66014851d6db1c8d89a07d024be2ecb page01.pre SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page01.pre'`" test 1974 -eq "$shar_count" || $echo 'page01.pre:' 'original size' '1974,' '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' &&

Again, we begin with server.cpp.  If you look closely you will see that the only difference between this and the Tutorial 5 implementation is a single comment. X


SHAR_EOF $shar_touch -am 0118202399 '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' e9e18b8add5d997189fb16e67d1467b2 page02.pre SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page02.pre'`" test 252 -eq "$shar_count" || $echo 'page02.pre:' 'original size' '252,' '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' &&

In client_acceptor.h, we've extended our object just a bit.  The primary reason is to allow us to select the previous single-threaded implementation or our new thread-per-connection implementation.  Client_Acceptor itself doesn't use this information but makes it available to the Client_Handler objects it creates.  If we wanted a single-strategy implementation, we would have made no changes to the Tutorial 5 version of this file. X


SHAR_EOF $shar_touch -am 0118202399 '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' 40dd465ac9815a2c35375ccdbad0c98b page03.pre SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page03.pre'`" test 507 -eq "$shar_count" || $echo 'page03.pre:' 'original size' '507,' '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' &&

client_handler.h shows a few more changes than the previous sources.  The important change is the addition of a svc() method where our connection thread will exist. X


SHAR_EOF $shar_touch -am 0118202399 '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' 8256aff03563fbc281403fc5bb970e69 page04.pre SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pre'`" test 227 -eq "$shar_count" || $echo 'page04.pre:' 'original size' '227,' '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' &&

client_handler.cpp exposes all the things I've been hinting at.  Pay special attention to the decision made in open() as well as the bit of cleverness in svc(). X


SHAR_EOF $shar_touch -am 0118202399 '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' 08278c0477a109e107b680424bf70a9d page05.pre SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page05.pre'`" test 231 -eq "$shar_count" || $echo 'page05.pre:' 'original size' '231,' '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' &&

That's it for Tutorial 6.  With very little effort we've managed to extend the previous single-threaded server to an implementation which allows runtime selection of single or multi-threaded operation.  In Tutorial 7 we'll extend that again to allow a thread-pool choice in addition to the current two. X

For reference, here's the file list again:

SHAR_EOF $shar_touch -am 0118202399 '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' 0adca372a5154acf673cc373d2acaf5a page06.pre SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page06.pre'`" test 697 -eq "$shar_count" || $echo 'page06.pre:' 'original size' '697,' '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' &&
X

Let's move along and see what happend to the Client_Acceptor. X

SHAR_EOF $shar_touch -am 0118202399 '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' 0188a5ff7cacc123676e420ac5432207 page02.pst SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page02.pst'`" test 89 -eq "$shar_count" || $echo 'page02.pst:' 'original size' '89,' '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' &&


X

Ok, so far we haven't done much to change our concurrency strategy.  Let's move on to the Client_Handler and see if it has changed any. X

SHAR_EOF $shar_touch -am 0118202399 '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' 7743577254d06f5848b5e50f3b6c3014 page03.pst SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page03.pst'`" test 168 -eq "$shar_count" || $echo 'page03.pst:' 'original size' '168,' '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' &&


X

So... we've added a svc() method and alluded to changes in open().  Let's move on to the object definition and see what all the fuss is about. X

SHAR_EOF $shar_touch -am 0118202399 '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' dfe0897cc3f000b69c16c87dd1596281 page04.pst SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pst'`" test 175 -eq "$shar_count" || $echo 'page04.pst:' 'original size' '175,' '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' &&


X Did you notice the THR_DETACHED flag on the call to X activate()? Threads, like any system resource, are a X limited resource. Unless we intend to join() or X wait() for the new thread later, we want use THR_DETACHED X so that we don't cause a leak. In fact, in most cases, you'll X want to specify THR_DETACHED because it's just easier.

X Another handy flag for use with activate() is X THR_NEW_LWP. That's short for Light Weight X Process. If you've got a multiprocessor, this flag will X allocate a new schedulable process and decrease the odds of your X threads all fighting for the same process. Of course, if you X have a uni-processor, it will neither help nor hurt. Since I X developed these on a uni-processor, I've been a bit inconsistent X in the use of THR_NEW_LWP. X

Well, that's it!  After all the talk & the hype, you would have expected it to be more difficult to create a multi-threaded server.  Surprise!  It really is that easy.  You still have to handle contention issues which we haven't addressed here and that is a rather nasty topic.  Still, for the simple case, this is all you have to do. X

The next page is the last for this tutorial.  Head on over there & we'll round up the file list one last time. X

SHAR_EOF $shar_touch -am 0921222699 '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' fab2e03eb2f115f89a58d70be291e87e page05.pst SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page05.pst'`" test 1420 -eq "$shar_count" || $echo 'page05.pst:' 'original size' '1420,' 'current size' "$shar_count!" fi fi rm -fr _sh04795 exit 0