summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjcej <jcej@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1998-11-10 20:33:32 +0000
committerjcej <jcej@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1998-11-10 20:33:32 +0000
commit922a655a3a371b2d749f59761843297c408a9d1a (patch)
treee38b3d81f61b5c36755dbe99aea61597089b8c32
parent120d21fda926fcdb6c866c26555b2beafe2e0e25 (diff)
downloadATCD-922a655a3a371b2d749f59761843297c408a9d1a.tar.gz
*** empty log message ***
-rw-r--r--ChangeLog-98b11
-rw-r--r--docs/tutorials/017/Barrier_i.cpp58
-rw-r--r--docs/tutorials/017/Barrier_i.h36
-rw-r--r--docs/tutorials/017/barrier.cpp90
-rw-r--r--docs/tutorials/017/combine.shar304
-rw-r--r--docs/tutorials/017/page01.html34
-rw-r--r--docs/tutorials/017/page02.html156
-rw-r--r--docs/tutorials/017/page03.html90
-rw-r--r--docs/tutorials/017/page04.html151
-rw-r--r--docs/tutorials/017/page05.html26
-rw-r--r--docs/tutorials/index.html3
11 files changed, 927 insertions, 32 deletions
diff --git a/ChangeLog-98b b/ChangeLog-98b
index 396dfdffabd..6b6879c6b05 100644
--- a/ChangeLog-98b
+++ b/ChangeLog-98b
@@ -1,3 +1,12 @@
+Tue Nov 10 14:56:38 EST 1998 James CE Johnson <jcej@chiroptera.tragus.org>
+
+ * docs/tutorials/index.html
+ Including #17 now
+
+ * docs/tutorials/017/*.html
+ docs/tutorials/017/combine.shar
+ Completed! Commented and converted into standared Tutorial format.
+
Tue Nov 10 10:09:06 1998 David L. Levine <levine@cs.wustl.edu>
* tests/Env_Value_Test.cpp (main): replaced hard-coded "/" with
@@ -141,7 +150,7 @@ Fri Nov 06 12:58:24 1998 Nanbor Wang <nanbor@cs.wustl.edu>
* ace/Thread_Manager.cpp: Removed several superfluous parens so
the code looks clearer and less error-prone.
-1998-11-06 James CE Johnson <jim@adt1.lads.com>
+1998-11-06 James CE Johnson <jcej@lads.com>
* docs/tutorials/013/block.cpp
* docs/tutorials/013/page05.html
diff --git a/docs/tutorials/017/Barrier_i.cpp b/docs/tutorials/017/Barrier_i.cpp
index b7063863a3e..a763c1d8273 100644
--- a/docs/tutorials/017/Barrier_i.cpp
+++ b/docs/tutorials/017/Barrier_i.cpp
@@ -3,6 +3,10 @@
#include "Barrier_i.h"
+/* Initialize the threads_ count to zero and the barrier_ pointer to a
+ safe value. At the same time, we remember the thread that created
+ us so that we can allow it to change the thread count.
+*/
Barrier::Barrier(void)
: threads_(0)
,barrier_(0)
@@ -10,17 +14,35 @@ Barrier::Barrier(void)
owner_ = ACE_OS::thr_self();
}
+/* Ensure that barrier_ get's deleted so that we don't have a memory leak.
+ */
Barrier::~Barrier(void)
{
- this->done();
+ delete barrier_;
}
+// Report on the number of threads.
u_int Barrier::threads(void)
{
return threads_.value();
}
-int Barrier::threads( u_int _threads )
+/* Allow the owning thread to (re)set the number of threads.
+ make_barrier() is called because it will wait() if we were already
+ configured. Typical usage would be for the worker threads to
+ wait() while the primary (eg -- owner) thread adjusts the thread
+ count.
+
+ For instance:
+ In the worker threads:
+ if( myBarrier.threads() != current_thread_count )
+ myBarrier.wait();
+
+ In the primary thread:
+ if( myBarrier.threads() != current_thread_count )
+ myBarrier.threads( current_thread_count, 1 );
+ */
+int Barrier::threads( u_int _threads, int _wait )
{
if( ACE_OS::thr_self() != owner_ )
{
@@ -29,9 +51,13 @@ int Barrier::threads( u_int _threads )
threads_ = _threads;
- return make_barrier();
+ return make_barrier(_wait);
}
+/* Wait for all threads to synch if the thread count is valid. Note
+ that barrier_ will be 0 if the threads() mutator has not been
+ invoked.
+*/
int Barrier::wait(void)
{
if( ! barrier_ )
@@ -42,6 +68,12 @@ int Barrier::wait(void)
return barrier_->wait();
}
+/* Wait for all threads to synch. As each thread passes wait(), it
+ will decrement our thread counter. (That is why we had to make
+ threads_ an atomic op.) When the last thread decrements the
+ counter it will also delete the ACE_Barrier & free up a little
+ memory.
+*/
int Barrier::done(void)
{
if( this->wait() == -1 )
@@ -60,19 +92,33 @@ int Barrier::done(void)
return 0;
}
-int Barrier::make_barrier(void)
+/* This will build the actual barrier. I broke this code out of the
+ threads() mutator in case it might be useful elsewhere.
+ If a barrier already exists, we will wait for all threads before
+ creating a new one. This trait is what allows the threads mutator
+ to be used as shown above.
+ */
+int Barrier::make_barrier( int _wait )
{
+ // Wait for and delete any existing barrier.
if( barrier_ )
{
- barrier_->wait();
+ if( _wait )
+ {
+ barrier_->wait();
+ }
delete barrier_;
}
+ // Ensure we have a valid thread count.
if( ! threads_.value() )
{
return -1;
}
-
+
+ // Create the actual barrier. Note that we initialize it with
+ // threads_.value() to set its internal thread count. If the
+ // 'new' fails we will return -1 to the caller.
ACE_NEW_RETURN(barrier_,ACE_Barrier(threads_.value()),-1);
return 0;
diff --git a/docs/tutorials/017/Barrier_i.h b/docs/tutorials/017/Barrier_i.h
index be0280effd1..49c862cfd3d 100644
--- a/docs/tutorials/017/Barrier_i.h
+++ b/docs/tutorials/017/Barrier_i.h
@@ -6,24 +6,54 @@
#include "ace/Synch.h"
+/* Barrier is a simple wrapper for the ACE_Barrier synchronization
+ class. The ACE_Barrier is already pretty easy to use but I thought
+ I'd wrap it up to create just a bit more abstraction at the
+ application level.
+ */
class Barrier
{
public:
+ // Basic constructor and destructor. If you only need to
+ // synch the start of your threads, you can safely delete your
+ // Barrier object after invoking done(). Of course, you
+ // should be careful to only delete the object once!
Barrier(void);
~Barrier(void);
- int threads( u_int _threads);
+ // Set and get the number of threads that the barrier will
+ // manage. If you add or remove threads to your application
+ // at run-time you can use the mutator to reflect that
+ // change. Note, however, that you can only do that from the
+ // thread which first created the Barrier. (This is a
+ // limitation of my Barrier object, not the ACE_Barrier.)
+ // The optional _wait parameter will cause wait() to be
+ // invoked if there is already a valid threads value.
+ int threads( u_int _threads, int _wait = 0);
u_int threads(void);
-
+
+ // Wait for all threads to reach the point where this is
+ // invoked. Because of the snappy way in which ACE_Barrier is
+ // implemented, you can invoke these back-to-back with no ill-effects.
int wait(void);
+
+ // done() will invoke wait(). Before returning though, it
+ // will delete the barrier_ pointer below to reclaim some memory.
int done(void);
protected:
+ // The number of threads we're synching
ACE_Atomic_Op<ACE_Mutex,u_int> threads_;
+
+ // The ACE_Barrier that does all of the work
ACE_Barrier * barrier_;
+
+ // The thread which created the Barrier in the first place.
+ // Only this thread can change the threads_ value.
ACE_thread_t owner_;
- int make_barrier(void);
+ // An internal method that constructs the barrier_ as needed.
+ int make_barrier( int _wait );
};
#endif // BARRIER_H
diff --git a/docs/tutorials/017/barrier.cpp b/docs/tutorials/017/barrier.cpp
index 9d6d01c8c16..287c3c8be8a 100644
--- a/docs/tutorials/017/barrier.cpp
+++ b/docs/tutorials/017/barrier.cpp
@@ -4,77 +4,125 @@
#include "Barrier_i.h"
#include "ace/Task.h"
+/* We'll use a simple Task<> derivative to test our new Barrier
+ object.
+*/
class Test : public ACE_Task<ACE_NULL_SYNCH>
{
public:
- Test(void);
- ~Test(void);
- int open(int _threads );
+ // Open the object with a few threads
+ int open(int _threads);
+
+ // Perform the test
int svc(void);
protected:
+ // The Barrier object we'll use in our tests below
Barrier barrier_;
};
-Test::Test(void)
-{
- ;
-}
-
-Test::~Test(void)
-{
- ;
-}
-
+/* As usual, our open() will create one or more threads where we'll do
+ the interesting work.
+*/
int Test::open( int _threads )
{
+ // One thing about the barrier: You have to tell it how many
+ // threads it will be synching. The threads() mutator on my
+ // Barrier class lets you do that and hides the implementation
+ // details at the same time.
barrier_.threads(_threads);
+
+ // Activate the tasks as usual...
return this->activate(THR_NEW_LWP, _threads);
}
+/* svc() will execute in each thread & do a few things with the
+ Barrier we have.
+ */
int Test::svc(void)
{
ACE_DEBUG ((LM_INFO, "(%P|%t|%T)\tTest::svc() Entry\n"));
-
+
+ // Initialize the random number generator. We'll use this to
+ // create sleep() times in each thread. This will help us see
+ // if the barrier synch is working.
ACE_RANDR_TYPE seed = ACE_OS::thr_self();
ACE_OS::srand(seed);
int delay;
-
+
+ // After saying hello above, sleep for a random amount of time
+ // from 1 to 6 seconds. That will cause the next message
+ // "Entering wait()" to be staggered on the output as each
+ // thread's sleep() returns.
delay = ACE_OS::rand_r(seed)%5;
ACE_OS::sleep(abs(delay)+1);
-
+
+ // When executing the app you should see these messages
+ // staggered in an at-most 6 second window. That is, you
+ // won't likely see them all at once.
ACE_DEBUG ((LM_INFO, "(%P|%t|%T)\tTest::svc() Entering wait()\n"));
- barrier_.wait();
-
+ // All of the threads will now wait at this point. As each
+ // thread finishes the sleep() above it will join the waiters.
+ if( barrier_.wait() == -1 )
+ {
+ ACE_DEBUG ((LM_INFO, "(%P|%t|%T)\tbarrier_.wait() failed!\n"));
+ return 0;
+ }
+
+ // When all threads have reached wait() they will give us this
+ // message. If you execute this, you should see all of the
+ // "Everybody together" messages at about the same time.
ACE_DEBUG ((LM_INFO, "(%P|%t|%T)\tTest::svc() Everybody together?\n"));
+ // Now we do the sleep() cycle again...
delay = ACE_OS::rand_r(seed)%5;
ACE_OS::sleep(abs(delay)+1);
+ // As before, these will trickle in over a few seconds.
ACE_DEBUG ((LM_INFO, "(%P|%t|%T)\tTest::svc() Entering done()\n"));
- barrier_.done();
-
+ // This time we call done() instead of wait(). done()
+ // actually invokes wait() but before returning here, it will
+ // clean up a few resources. The goal is to prevent carrying
+ // around objects you don't need.
+ if( barrier_.wait() == -1 )
+ {
+ ACE_DEBUG ((LM_INFO, "(%P|%t|%T)\tbarrier_.done() failed!\n"));
+ return 0;
+ }
+
+ // Since done() invokes wait() internally, we'll see this
+ // message from each thread simultaneously
ACE_DEBUG ((LM_INFO, "(%P|%t|%T)\tTest::svc() Is everyone still here?\n"));
-
+
+ // A final sleep()
delay = ACE_OS::rand_r(seed)%5;
ACE_OS::sleep(abs(delay)+1);
+ // These should be randomly spaced like all of the other
+ // post-sleep messages.
ACE_DEBUG ((LM_INFO, "(%P|%t|%T)\tTest::svc() Chaos and anarchy for all!\n"));
return(0);
}
+/* Our test application...
+ */
int main(int, char**)
{
+ // Create the test object
Test test;
+ // and open it with 10 threads.
test.open(10);
+ // Now wait for them all to exit.
test.wait();
+ // Re-open the Test object with just 5 threads
test.open(5);
+ // and wait for them to complete also.
test.wait();
return(0);
diff --git a/docs/tutorials/017/combine.shar b/docs/tutorials/017/combine.shar
new file mode 100644
index 00000000000..7e826ed7928
--- /dev/null
+++ b/docs/tutorials/017/combine.shar
@@ -0,0 +1,304 @@
+#!/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 1998-11-10 14:42 EST by <jcej@caldera.lads.com>.
+# Source directory was `/scsiA/home/jcej/projects/ACE_wrappers/docs/tutorials/017'.
+#
+# Existing files will *not* be overwritten unless `-c' is specified.
+#
+# This shar contains:
+# length mode name
+# ------ ---------- ------------------------------------------
+# 422 -rw-rw-r-- hdr
+# 44 -rw-rw-r-- bodies
+# 843 -rw-rw-r-- page01.pre
+# 419 -rw-rw-r-- page02.pre
+# 739 -rw-rw-r-- page03.pre
+# 478 -rw-rw-r-- page04.pre
+# 375 -rw-rw-r-- page05.pre
+#
+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 _sh01874; 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="Author" CONTENT="James CE Johnson">
+X <TITLE>ACE Tutorial 017</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+X
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 017</FONT></B></CENTER>
+X
+<CENTER><B><FONT SIZE=+2>Using the ACE_Barrier synch object</FONT></B></CENTER>
+X
+<P>
+<HR WIDTH="100%">
+SHAR_EOF
+ $shar_touch -am 1110144198 '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'
+9991b747f6aff75784cbeb88a79c06fc hdr
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'hdr'`"
+ test 422 -eq "$shar_count" ||
+ $echo 'hdr:' 'original size' '422,' '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
+barrier.cpp
+Barrier_i.h
+Barrier_i.cpp
+SHAR_EOF
+ $shar_touch -am 1110144198 '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'
+1b7c57aab2c61f845219723b8558bea6 bodies
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'bodies'`"
+ test 44 -eq "$shar_count" ||
+ $echo 'bodies:' 'original size' '44,' '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' &&
+The ACE_Barrier implements the barrier synchronization pattern.
+<P>
+That's nice. What does it mean?
+<P>
+What it means is that you can use the ACE_Barrier to cause a set of
+threads to all wait at a specific point in your application. In other
+words: the threads reach a barrier that none can pass until all are
+present.
+<P>
+This would typically be used in scientific applications where a set of
+threads are all working in parallel on some great computation but they
+have to synch and summarize before continuing to the next stage of calculation. With
+proper use of ACE_Barrier, the threads can easily synch before
+continuing.
+<P>
+In this tutorial I'll create a simple wrapper for the ACE_Barrier. In
+reality, the ACE_Barrier is so easy that a wrapper isn't really
+needed. I created the wrapper anyway though just because I wanted to.
+SHAR_EOF
+ $shar_touch -am 1110144198 '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'
+30840e2b3e8bf84d94abb9177bffbbec page01.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page01.pre'`"
+ test 843 -eq "$shar_count" ||
+ $echo 'page01.pre:' 'original size' '843,' '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' &&
+First, lets take a look at the main() routine and how it will use the
+Barrier wrapper class. A simple ACE_Task derivative is used so that
+we can perform work in multiple threads. These threads will use the
+barrier to synch in a couple of places.
+<P>
+Obviously this isn't a very realistic example but you should be able
+to get the idea of how to use a Barrier without getting hung up in
+application-level details.
+<HR>
+SHAR_EOF
+ $shar_touch -am 1110144198 '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'
+72dd8d286e36d8911945824bf2c91cc3 page02.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page02.pre'`"
+ test 419 -eq "$shar_count" ||
+ $echo 'page02.pre:' 'original size' '419,' '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' &&
+The Barrier class used by the test task is a simple wrapper around
+ACE_Barrier. One of the things about ACE_Barrier is that you have to
+tell it how many threads it will be managing. Since that number
+usually isn't known when you create your Task derivative, you have to
+dynamically allocate the ACE_Barrier. My Barrier wrapper takes care
+of that for you and even provides for a clean way to delete the
+ACE_Barrier instance if you want to save a few bytes.
+<P>
+An interesting extension of this Barrier class would be to wrap it up
+in a smart pointer. You could then have the Barrier destructor invoke
+wait() as a now-protected method. The result would allow you to treat
+the Barrier object almost as a "synchronization guard".
+<HR>
+SHAR_EOF
+ $shar_touch -am 1110144198 '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'
+6fc63f76eb4ac94dd6a8b45393613e7c page03.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page03.pre'`"
+ test 739 -eq "$shar_count" ||
+ $echo 'page03.pre:' 'original size' '739,' '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' &&
+The Barrier implementation is quite simple. The threads() mutator
+took a couple of tries to get right. In particular, be sure you know
+when to apply the _wait paramter and when not to! In fact, the
+requirement that only the "owning" thread can change the thread count
+is rather limiting. A more appropriate solution would allow any
+thread to safely change the count but that would require more complex
+locking that is just a bit more than what I wanted to present here.
+<HR>
+SHAR_EOF
+ $shar_touch -am 1110144198 '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'
+bed05089cb64c075cceec277e2a7da5f page04.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pre'`"
+ test 478 -eq "$shar_count" ||
+ $echo 'page04.pre:' 'original size' '478,' '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' &&
+Well, that's it for the simple Barrier Tutorial. I encourage you to
+try it out and see what you like and dislike. Any improvements or
+enhancements will gladly be integrated into the Tutorial.
+<P>
+<UL>
+<LI><A HREF="Makefile">Makefile</A>
+<LI><A HREF="barrier.cpp">barrier.cpp</A>
+<LI><A HREF="Barrier_i.h">Barrier_i.h</A>
+<LI><A HREF="Barrier_i.cpp">Barrier_i.cpp</A>
+</UL>
+SHAR_EOF
+ $shar_touch -am 1110144198 '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'
+616a2293adddb11896d28c7172436a65 page05.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page05.pre'`"
+ test 375 -eq "$shar_count" ||
+ $echo 'page05.pre:' 'original size' '375,' 'current size' "$shar_count!"
+ fi
+fi
+rm -fr _sh01874
+exit 0
diff --git a/docs/tutorials/017/page01.html b/docs/tutorials/017/page01.html
new file mode 100644
index 00000000000..d88f8e401f0
--- /dev/null
+++ b/docs/tutorials/017/page01.html
@@ -0,0 +1,34 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 017</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 017</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Using the ACE_Barrier synch object</FONT></B></CENTER>
+
+<P>
+<HR WIDTH="100%">
+The ACE_Barrier implements the barrier synchronization pattern.
+<P>
+That's nice. What does it mean?
+<P>
+What it means is that you can use the ACE_Barrier to cause a set of
+threads to all wait at a specific point in your application. In other
+words: the threads reach a barrier that none can pass until all are
+present.
+<P>
+This would typically be used in scientific applications where a set of
+threads are all working in parallel on some great computation but they
+have to synch and summarize before continuing to the next stage of calculation. With
+proper use of ACE_Barrier, the threads can easily synch before
+continuing.
+<P>
+In this tutorial I'll create a simple wrapper for the ACE_Barrier. In
+reality, the ACE_Barrier is so easy that a wrapper isn't really
+needed. I created the wrapper anyway though just because I wanted to.
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page02.html">Continue This Tutorial</A>]</CENTER>
diff --git a/docs/tutorials/017/page02.html b/docs/tutorials/017/page02.html
new file mode 100644
index 00000000000..c6e8b05490e
--- /dev/null
+++ b/docs/tutorials/017/page02.html
@@ -0,0 +1,156 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 017</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 017</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Using the ACE_Barrier synch object</FONT></B></CENTER>
+
+<P>
+<HR WIDTH="100%">
+First, lets take a look at the main() routine and how it will use the
+Barrier wrapper class. A simple ACE_Task derivative is used so that
+we can perform work in multiple threads. These threads will use the
+barrier to synch in a couple of places.
+<P>
+Obviously this isn't a very realistic example but you should be able
+to get the idea of how to use a Barrier without getting hung up in
+application-level details.
+<HR>
+<PRE>
+
+<font color=red>// $Id$</font>
+
+<font color=blue>#include</font> "<font color=green>Barrier_i.h</font>"
+<font color=blue>#include</font> "<font color=green>ace/Task.h</font>"
+
+<font color=red>/* We'll use a simple Task&lt;> derivative to test our new Barrier
+ object.
+*/</font>
+class Test : public ACE_Task&lt;ACE_NULL_SYNCH>
+{
+public:
+
+ <font color=red>// Open the object with a few threads</font>
+ int open(int _threads);
+
+ <font color=red>// Perform the test</font>
+ int svc(void);
+
+protected:
+ <font color=red>// The Barrier object we'll use in our tests below</font>
+ Barrier barrier_;
+};
+
+<font color=red>/* As usual, our open() will create one or more threads where we'll do
+ the interesting work.
+*/</font>
+int <font color=#008888>Test::open</font>( int _threads )
+{
+ <font color=red>// One thing about the barrier: You have to tell it how many</font>
+ <font color=red>// threads it will be synching. The threads() mutator on my</font>
+ <font color=red>// Barrier class lets you do that and hides the implementation </font>
+ <font color=red>// details at the same time.</font>
+ barrier_.threads(_threads);
+
+ <font color=red>// Activate the tasks as usual...</font>
+ return this->activate(THR_NEW_LWP, _threads);
+}
+
+<font color=red>/* svc() will execute in each thread & do a few things with the
+ Barrier we have.
+ */</font>
+int <font color=#008888>Test::svc</font>(void)
+{
+ ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t|%T)\<font color=#008888>tTest::svc</font>() Entry\n</font>"));
+
+ <font color=red>// Initialize the random number generator. We'll use this to</font>
+ <font color=red>// create sleep() times in each thread. This will help us see </font>
+ <font color=red>// if the barrier synch is working.</font>
+ ACE_RANDR_TYPE seed = <font color=#008888>ACE_OS::thr_self</font>();
+ <font color=#008888>ACE_OS::srand</font>(seed);
+ int delay;
+
+ <font color=red>// After saying hello above, sleep for a random amount of time </font>
+ <font color=red>// from 1 to 6 seconds. That will cause the next message</font>
+ <font color=red>// "<font color=green>Entering wait()</font>" to be staggered on the output as each</font>
+ <font color=red>// thread's sleep() returns.</font>
+ delay = <font color=#008888>ACE_OS::rand_r</font>(seed)%5;
+ <font color=#008888>ACE_OS::sleep</font>(abs(delay)+1);
+
+ <font color=red>// When executing the app you should see these messages</font>
+ <font color=red>// staggered in an at-most 6 second window. That is, you</font>
+ <font color=red>// won't likely see them all at once.</font>
+ ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t|%T)\<font color=#008888>tTest::svc</font>() Entering wait()\n</font>"));
+
+ <font color=red>// All of the threads will now wait at this point. As each</font>
+ <font color=red>// thread finishes the sleep() above it will join the waiters.</font>
+ if( barrier_.wait() == -1 )
+ {
+ ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t|%T)\tbarrier_.wait() failed!\n</font>"));
+ return 0;
+ }
+
+ <font color=red>// When all threads have reached wait() they will give us this </font>
+ <font color=red>// message. If you execute this, you should see all of the</font>
+ <font color=red>// "<font color=green>Everybody together</font>" messages at about the same time.</font>
+ ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t|%T)\<font color=#008888>tTest::svc</font>() Everybody together?\n</font>"));
+
+ <font color=red>// Now we do the sleep() cycle again...</font>
+ delay = <font color=#008888>ACE_OS::rand_r</font>(seed)%5;
+ <font color=#008888>ACE_OS::sleep</font>(abs(delay)+1);
+
+ <font color=red>// As before, these will trickle in over a few seconds.</font>
+ ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t|%T)\<font color=#008888>tTest::svc</font>() Entering done()\n</font>"));
+
+ <font color=red>// This time we call done() instead of wait(). done()</font>
+ <font color=red>// actually invokes wait() but before returning here, it will </font>
+ <font color=red>// clean up a few resources. The goal is to prevent carrying</font>
+ <font color=red>// around objects you don't need.</font>
+ if( barrier_.wait() == -1 )
+ {
+ ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t|%T)\tbarrier_.done() failed!\n</font>"));
+ return 0;
+ }
+
+ <font color=red>// Since done() invokes wait() internally, we'll see this</font>
+ <font color=red>// message from each thread simultaneously</font>
+ ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t|%T)\<font color=#008888>tTest::svc</font>() Is everyone still here?\n</font>"));
+
+ <font color=red>// A final sleep()</font>
+ delay = <font color=#008888>ACE_OS::rand_r</font>(seed)%5;
+ <font color=#008888>ACE_OS::sleep</font>(abs(delay)+1);
+
+ <font color=red>// These should be randomly spaced like all of the other</font>
+ <font color=red>// post-sleep messages.</font>
+ ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t|%T)\<font color=#008888>tTest::svc</font>() Chaos and anarchy for all!\n</font>"));
+
+ return(0);
+}
+
+<font color=red>/* Our test application...
+ */</font>
+int main(int, char**)
+{
+ <font color=red>// Create the test object</font>
+ Test test;
+
+ <font color=red>// and open it with 10 threads.</font>
+ test.open(10);
+ <font color=red>// Now wait for them all to exit.</font>
+ test.wait();
+
+ <font color=red>// Re-open the Test object with just 5 threads</font>
+ test.open(5);
+ <font color=red>// and wait for them to complete also.</font>
+ test.wait();
+
+ return(0);
+}
+</PRE>
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page03.html">Continue This Tutorial</A>]</CENTER>
diff --git a/docs/tutorials/017/page03.html b/docs/tutorials/017/page03.html
new file mode 100644
index 00000000000..4513ed2260c
--- /dev/null
+++ b/docs/tutorials/017/page03.html
@@ -0,0 +1,90 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 017</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 017</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Using the ACE_Barrier synch object</FONT></B></CENTER>
+
+<P>
+<HR WIDTH="100%">
+The Barrier class used by the test task is a simple wrapper around
+ACE_Barrier. One of the things about ACE_Barrier is that you have to
+tell it how many threads it will be managing. Since that number
+usually isn't known when you create your Task derivative, you have to
+dynamically allocate the ACE_Barrier. My Barrier wrapper takes care
+of that for you and even provides for a clean way to delete the
+ACE_Barrier instance if you want to save a few bytes.
+<P>
+An interesting extension of this Barrier class would be to wrap it up
+in a smart pointer. You could then have the Barrier destructor invoke
+wait() as a now-protected method. The result would allow you to treat
+the Barrier object almost as a "synchronization guard".
+<HR>
+<PRE>
+
+<font color=red>// $Id$</font>
+
+<font color=blue>#ifndef</font> <font color=purple>BARRIER_H</font>
+<font color=blue>#define</font> <font color=purple>BARRIER_H</font>
+
+<font color=blue>#include</font> "<font color=green>ace/Synch.h</font>"
+
+<font color=red>/* Barrier is a simple wrapper for the ACE_Barrier synchronization
+ class. The ACE_Barrier is already pretty easy to use but I thought
+ I'd wrap it up to create just a bit more abstraction at the
+ application level.
+ */</font>
+class Barrier
+{
+public:
+ <font color=red>// Basic constructor and destructor. If you only need to</font>
+ <font color=red>// synch the start of your threads, you can safely delete your </font>
+ <font color=red>// Barrier object after invoking done(). Of course, you</font>
+ <font color=red>// should be careful to only delete the object once!</font>
+ Barrier(void);
+ ~Barrier(void);
+
+ <font color=red>// Set and get the number of threads that the barrier will</font>
+ <font color=red>// manage. If you add or remove threads to your application</font>
+ <font color=red>// at run-time you can use the mutator to reflect that</font>
+ <font color=red>// change. Note, however, that you can only do that from the</font>
+ <font color=red>// thread which first created the Barrier. (This is a</font>
+ <font color=red>// limitation of my Barrier object, not the ACE_Barrier.)</font>
+ <font color=red>// The optional _wait parameter will cause wait() to be</font>
+ <font color=red>// invoked if there is already a valid threads value.</font>
+ int threads( u_int _threads, int _wait = 0);
+ u_int threads(void);
+
+ <font color=red>// Wait for all threads to reach the point where this is</font>
+ <font color=red>// invoked. Because of the snappy way in which ACE_Barrier is </font>
+ <font color=red>// implemented, you can invoke these back-to-back with no ill-effects.</font>
+ int wait(void);
+
+ <font color=red>// done() will invoke wait(). Before returning though, it</font>
+ <font color=red>// will delete the barrier_ pointer below to reclaim some memory.</font>
+ int done(void);
+
+protected:
+ <font color=red>// The number of threads we're synching</font>
+ ACE_Atomic_Op&lt;ACE_Mutex,u_int> threads_;
+
+ <font color=red>// The ACE_Barrier that does all of the work</font>
+ ACE_Barrier * barrier_;
+
+ <font color=red>// The thread which created the Barrier in the first place.</font>
+ <font color=red>// Only this thread can change the threads_ value.</font>
+ ACE_thread_t owner_;
+
+ <font color=red>// An internal method that constructs the barrier_ as needed.</font>
+ int make_barrier( int _wait );
+};
+
+<font color=blue>#endif</font> <font color=red>// BARRIER_H</font>
+</PRE>
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page04.html">Continue This Tutorial</A>]</CENTER>
diff --git a/docs/tutorials/017/page04.html b/docs/tutorials/017/page04.html
new file mode 100644
index 00000000000..958244cf3c9
--- /dev/null
+++ b/docs/tutorials/017/page04.html
@@ -0,0 +1,151 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 017</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 017</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Using the ACE_Barrier synch object</FONT></B></CENTER>
+
+<P>
+<HR WIDTH="100%">
+The Barrier implementation is quite simple. The threads() mutator
+took a couple of tries to get right. In particular, be sure you know
+when to apply the _wait paramter and when not to! In fact, the
+requirement that only the "owning" thread can change the thread count
+is rather limiting. A more appropriate solution would allow any
+thread to safely change the count but that would require more complex
+locking that is just a bit more than what I wanted to present here.
+<HR>
+<PRE>
+
+<font color=red>// $Id$</font>
+
+<font color=blue>#include</font> "<font color=green>Barrier_i.h</font>"
+
+<font color=red>/* Initialize the threads_ count to zero and the barrier_ pointer to a
+ safe value. At the same time, we remember the thread that created
+ us so that we can allow it to change the thread count.
+*/</font>
+<font color=#008888>Barrier::Barrier</font>(void)
+ : threads_(0)
+ ,barrier_(0)
+{
+ owner_ = <font color=#008888>ACE_OS::thr_self</font>();
+}
+
+<font color=red>/* Ensure that barrier_ get's deleted so that we don't have a memory leak.
+ */</font>
+<font color=#008888>Barrier::~Barrier</font>(void)
+{
+ delete barrier_;
+}
+
+<font color=red>// Report on the number of threads.</font>
+u_int <font color=#008888>Barrier::threads</font>(void)
+{
+ return threads_.value();
+}
+
+<font color=red>/* Allow the owning thread to (re)set the number of threads.
+ make_barrier() is called because it will wait() if we were already
+ configured. Typical usage would be for the worker threads to
+ wait() while the primary (eg -- owner) thread adjusts the thread
+ count.
+
+ For instance:
+ In the worker threads:
+ if( myBarrier.threads() != current_thread_count )
+ myBarrier.wait();
+
+ In the primary thread:
+ if( myBarrier.threads() != current_thread_count )
+ myBarrier.threads( current_thread_count, 1 );
+ */</font>
+int <font color=#008888>Barrier::threads</font>( u_int _threads, int _wait )
+{
+ if( <font color=#008888>ACE_OS::thr_self</font>() != owner_ )
+ {
+ return -1;
+ }
+
+ threads_ = _threads;
+
+ return make_barrier(_wait);
+}
+
+<font color=red>/* Wait for all threads to synch if the thread count is valid. Note
+ that barrier_ will be 0 if the threads() mutator has not been
+ invoked.
+*/</font>
+int <font color=#008888>Barrier::wait</font>(void)
+{
+ if( ! barrier_ )
+ {
+ return -1;
+ }
+
+ return barrier_->wait();
+}
+
+<font color=red>/* Wait for all threads to synch. As each thread passes wait(), it
+ will decrement our thread counter. (That is why we had to make
+ threads_ an atomic op.) When the last thread decrements the
+ counter it will also delete the ACE_Barrier & free up a little
+ memory.
+*/</font>
+int <font color=#008888>Barrier::done</font>(void)
+{
+ if( this->wait() == -1 )
+ {
+ return -1;
+ }
+
+ --threads_;
+
+ if( ! threads_.value() )
+ {
+ delete barrier_;
+ barrier_ = 0;
+ }
+
+ return 0;
+}
+
+<font color=red>/* This will build the actual barrier. I broke this code out of the
+ threads() mutator in case it might be useful elsewhere.
+ If a barrier already exists, we will wait for all threads before
+ creating a new one. This trait is what allows the threads mutator
+ to be used as shown above.
+ */</font>
+int <font color=#008888>Barrier::make_barrier</font>( int _wait )
+{
+ <font color=red>// Wait for and delete any existing barrier.</font>
+ if( barrier_ )
+ {
+ if( _wait )
+ {
+ barrier_->wait();
+ }
+ delete barrier_;
+ }
+
+ <font color=red>// Ensure we have a valid thread count.</font>
+ if( ! threads_.value() )
+ {
+ return -1;
+ }
+
+ <font color=red>// Create the actual barrier. Note that we initialize it with </font>
+ <font color=red>// threads_.value() to set its internal thread count. If the</font>
+ <font color=red>// 'new' fails we will return -1 to the caller.</font>
+ ACE_NEW_RETURN(barrier_,ACE_Barrier(threads_.value()),-1);
+
+ return 0;
+}
+</PRE>
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page05.html">Continue This Tutorial</A>]</CENTER>
diff --git a/docs/tutorials/017/page05.html b/docs/tutorials/017/page05.html
new file mode 100644
index 00000000000..9e2f29de5e1
--- /dev/null
+++ b/docs/tutorials/017/page05.html
@@ -0,0 +1,26 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 017</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 017</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Using the ACE_Barrier synch object</FONT></B></CENTER>
+
+<P>
+<HR WIDTH="100%">
+Well, that's it for the simple Barrier Tutorial. I encourage you to
+try it out and see what you like and dislike. Any improvements or
+enhancements will gladly be integrated into the Tutorial.
+<P>
+<UL>
+<LI><A HREF="Makefile">Makefile</A>
+<LI><A HREF="barrier.cpp">barrier.cpp</A>
+<LI><A HREF="Barrier_i.h">Barrier_i.h</A>
+<LI><A HREF="Barrier_i.cpp">Barrier_i.cpp</A>
+</UL>
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="..">Tutorial Index</A>] </CENTER>
diff --git a/docs/tutorials/index.html b/docs/tutorials/index.html
index f9ec9b48f29..f56cde885a6 100644
--- a/docs/tutorials/index.html
+++ b/docs/tutorials/index.html
@@ -106,15 +106,16 @@ Paddling down (and up) the ACE_Stream</H4>
<A HREF="015/page01.html">A certain amount of Protocol is required!</A></LI>
</OL>
+<P><HR WIDTH="50%" align=left><P>
<H4>
Keeping yourself in synch</H4>
<OL>
<LI>
<A HREF="016/page01.html">On one condition...</A>
-<!--
<LI>
<A HREF="017/page01.html">Something about Barriers</A>
+<!--
<LI>
<A HREF="018/page01.html">Tokens: Not just for the subway any more</A>
-->