summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjcej <jcej@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1998-10-29 19:38:53 +0000
committerjcej <jcej@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1998-10-29 19:38:53 +0000
commitdec63e599a47fdc3c6d3e7bcb0d706fe7f325851 (patch)
treee5c7a8280f3a0e5a32cd98df51d6e5e4f4dd088a
parente9493c1193c6b332ce009de40924034c480c147b (diff)
downloadATCD-dec63e599a47fdc3c6d3e7bcb0d706fe7f325851.tar.gz
*** empty log message ***
-rw-r--r--ChangeLog-98b7
-rw-r--r--docs/tutorials/016/Condition_i.cpp201
-rw-r--r--docs/tutorials/016/Condition_i.h159
-rw-r--r--docs/tutorials/016/Makefile74
-rw-r--r--docs/tutorials/016/combine.shar332
-rw-r--r--docs/tutorials/016/condition.cpp249
-rw-r--r--docs/tutorials/016/page01.html31
-rw-r--r--docs/tutorials/016/page02.html221
-rw-r--r--docs/tutorials/016/page03.html224
-rw-r--r--docs/tutorials/016/page04.html272
-rw-r--r--docs/tutorials/016/page05.html30
-rw-r--r--docs/tutorials/index.html14
12 files changed, 1814 insertions, 0 deletions
diff --git a/ChangeLog-98b b/ChangeLog-98b
index 2abaecc6bfd..b0eb10ff812 100644
--- a/ChangeLog-98b
+++ b/ChangeLog-98b
@@ -1,3 +1,10 @@
+Thu Oct 29 15:13:07 EST 1998 James CE Johnson <jcej@chiroptera.tragus.org>
+
+ * docs/tutorials/index.html
+ * docs/tutorials/016/*
+ Added Tutorial 016. This discusses ACE_Condition<> and ways
+ to make it more manageable in an application.
+
Thu Oct 29 11:44:21 1998 David L. Levine <levine@cs.wustl.edu>
* ace/config-sunos5.6.h: changed ACE_THREAD_POSIX_SEM to
diff --git a/docs/tutorials/016/Condition_i.cpp b/docs/tutorials/016/Condition_i.cpp
new file mode 100644
index 00000000000..82830bd7374
--- /dev/null
+++ b/docs/tutorials/016/Condition_i.cpp
@@ -0,0 +1,201 @@
+
+// $Id$
+
+// Get or declaration
+#include "Condition_i.h"
+
+/* Initialize the condition variable and create the condition mutex.
+ Since I don't have any guarantees on the order of member variable
+ initialization, I have to new the condition mutex instead of
+ simply constructing it.
+ */
+Condition::Condition(value_t _value)
+ : value_(_value)
+{
+ condition_ = new condition_t( this->mutex() );
+}
+
+Condition::~Condition(void)
+{
+ // Be sure we don't have a memeory leak
+ delete condition_;
+}
+
+/* The cast operator is the easiest way to return a copy of the value
+ to clients of the class. It also allows us to use a private method
+ for getting a reference to the value when we need to modify it.
+ */
+Condition::operator value_t (void)
+{
+ // Place a guard around the variable so that it won't change as
+ // we're copying it back to the client.
+ guard_t guard(mutex_);
+ return value();
+}
+
+/* Traditional prefix increment operator.
+ We place a guard around the operation so that we don't collide with
+ any other threads. After the modification, we broadcast() a
+ condition change to any waiting threads. You can also use signal()
+ but that will only tell one thread about the change. If that
+ thread, in turn, invokes signal() then all threads will eventually
+ find out. I just thought it would be easier to use broadcast() and
+ be done with it.
+ */
+Condition & Condition::operator++ (void)
+{
+ guard_t guard(mutex_);
+
+ ++value();
+
+ condition().broadcast();
+
+ return *this;
+}
+
+/* The remaining operators all follow the same pattern that we have
+ above. They only differ in the modification they make to the value().
+ */
+
+Condition & Condition::operator-- (void)
+{
+ guard_t guard(mutex_);
+
+ --value();
+
+ condition().broadcast();
+
+ return *this;
+}
+
+Condition & Condition::operator+= (int _inc)
+{
+ guard_t guard(mutex_);
+
+ value() += _inc;
+
+ condition().broadcast();
+
+ return *this;
+}
+
+Condition & Condition::operator-= (int _inc)
+{
+ guard_t guard(mutex_);
+
+ value() -= _inc;
+
+ condition().broadcast();
+
+ return *this;
+}
+
+Condition & Condition::operator*= (int _inc)
+{
+ guard_t guard(mutex_);
+
+ value() *= _inc;
+
+ condition().broadcast();
+
+ return *this;
+}
+
+Condition & Condition::operator/= (int _inc)
+{
+ guard_t guard(mutex_);
+
+ value() /= _inc;
+
+ condition().broadcast();
+
+ return *this;
+}
+
+Condition & Condition::operator%= (int _inc)
+{
+ guard_t guard(mutex_);
+
+ value() %= _inc;
+
+ condition().broadcast();
+
+ return *this;
+}
+
+Condition & Condition::operator= ( value_t _value )
+{
+ guard_t guard(mutex_);
+
+ value() = _value;
+
+ condition().broadcast();
+
+ return *this;
+}
+
+/* Now we get into the comparison area.
+ Each one follows the pattern we've already established for
+ waiters.
+ */
+
+/*
+ We begin with an equality operator that expects a function object.
+ In the while() test we pass a copy of the value to the function
+ object for evaluation. The object can then do any comparision it
+ wants to check for a desired condition. When the function object
+ returns non-zero, the condition is met and we leave.
+ */
+int Condition::operator== ( Condition::Compare & _compare )
+{
+ guard_t guard(mutex_);
+
+ while( ! _compare(this->value()) )
+ condition().wait();
+
+ return 0;
+}
+
+// As long as the variable equals _value, we wait...
+int Condition::operator== ( value_t _value )
+{
+ guard_t guard(mutex_);
+
+ while( value() == _value )
+ condition().wait();
+
+ return 0;
+}
+
+// As long as the variable is not equal to _value, we wait...
+int Condition::operator!= ( value_t _value )
+{
+ guard_t guard(mutex_);
+
+ while( value() != _value )
+ condition().wait();
+
+ return 0;
+}
+
+// As long as the variable is less than or equal to _value, we wait...
+int Condition::operator<= ( value_t _value )
+{
+ guard_t guard(mutex_);
+
+ while( value() <= _value )
+ condition().wait();
+
+ return 0;
+}
+
+// As long as the variable is greater than or equal to _value, we wait...
+int Condition::operator>= ( value_t _value )
+{
+ guard_t guard(mutex_);
+
+ while( value() >= _value )
+ condition().wait();
+
+ return 0;
+}
diff --git a/docs/tutorials/016/Condition_i.h b/docs/tutorials/016/Condition_i.h
new file mode 100644
index 00000000000..1bbc704af6f
--- /dev/null
+++ b/docs/tutorials/016/Condition_i.h
@@ -0,0 +1,159 @@
+
+// $Id$
+
+#ifndef CONDITION_H
+#define CONDITION_H
+
+#include "ace/Synch.h"
+
+/** A wrapper for ACE_Condition<>.
+ When you're using an ACE_Condition<> you have to have three things:
+ - Some variable that embodies the condition you're looking for
+ - A mutex to prevent simultaneous access to that variable from different threads
+ - An ACE_Condition<> that enables blocking on state changes in the variable
+ The class I create here will contain those three things. For the
+ actual condition variable I've chosen an integer. You could
+ easily turn this clas into a template parameterized on the
+ condition variable's data type if 'int' isn't what you want.
+ */
+class Condition
+{
+public:
+ // From here on I'll use value_t instead of 'int' to make any
+ // future upgrades easier.
+ typedef int value_t;
+
+ // Initialize the condition variable
+ Condition(value_t _value = 0);
+ ~Condition(void);
+
+ /* I've created a number of arithmetic operators on the class
+ that pass their operation on to the variable. If you turn
+ this into a template then some of these may not be
+ appropriate...
+ For the ones that take a parameter, I've stuck with 'int'
+ instead of 'value_t' to reinforce the fact that you'll need
+ a close look at these if you choose to change the 'value_t'
+ typedef.
+ */
+
+ // Increment & decrement
+ Condition & operator++(void);
+ Condition & operator--(void);
+
+ // Increase & decrease
+ Condition & operator+=(int _inc);
+ Condition & operator-=(int _inc);
+
+ // Just to be complete
+ Condition & operator*=(int _inc);
+ Condition & operator/=(int _inc);
+ Condition & operator%=(int _inc);
+
+ // Set/Reset the condition variable's value
+ Condition & operator=( value_t _value );
+
+ /* These four operators perform the actual waiting. For
+ instance:
+
+ operator!=(int _value)
+
+ is implemented as:
+
+ Guard guard(mutex_)
+ while( value_ != _value )
+ condition_.wait();
+
+ This is the "typical" use for condition mutexes. Each of
+ the operators below behaves this way for their respective
+ comparisions.
+
+ To use one of these in code, you would simply do:
+
+ Condition mycondition;
+ ...
+ // Wait until the condition variable has the value 42
+ mycondition != 42
+ ...
+ */
+
+ // As long as the condition variable is NOT EQUAL TO _value, we wait
+ int operator!=( value_t _value );
+ // As long as the condition variable is EXACTLY EQUAL TO _value, we wait
+ int operator==( value_t _value );
+ // As long as the condition variable is LESS THAN OR EQUAL TO _value, we wait
+ int operator<=( value_t _value );
+ // As long as the condition variable is GREATER THAN OR EQUAL TO _value, we wait
+ int operator>=( value_t _value );
+
+ // Return the value of the condition variable
+ operator value_t (void);
+
+ /* In addition to the four ways of waiting above, I've also
+ create a method that will invoke a function object for each
+ iteration of the while() loop.
+ Derive yourself an object from Condition::Compare and
+ overload operator()(value_t) to take advantage of this. Have
+ the function return non-zero when you consider the condition
+ to be met.
+ */
+ class Compare
+ {
+ public:
+ virtual int operator() ( value_t _value ) = 0;
+ };
+
+ /* Wait on the condition until _compare(value) returns
+ non-zero. This is a little odd since we're not really testing
+ equality. Just be sure that _compare(value_) will return
+ non-zero when you consider the condition to be met.
+ */
+ int operator==( Compare & _compare );
+
+private:
+ // Prevent copy construction and assignment.
+ Condition( const Condition & _condition );
+ Condition & operator= ( const Condition & _condition );
+
+ /* Typedefs make things easier to change later.
+ ACE_Condition_Thread_Mutex is used as a shorthand for
+ ACE_Condition<ACE_Thread_Mutex> and also because it may
+ provide optimizations we can use.
+ */
+ typedef ACE_Thread_Mutex mutex_t;
+ typedef ACE_Condition_Thread_Mutex condition_t;
+ typedef ACE_Guard<mutex_t> guard_t;
+
+ // The mutex that keeps the data save
+ mutex_t mutex_;
+
+ // The condition mutex that makes waiting on the condition
+ // easier.
+ condition_t * condition_;
+
+ // The acutal variable that embodies the condition we're
+ // waiting for.
+ value_t value_;
+
+ // Accessors for the two mutexes.
+ mutex_t & mutex(void)
+ {
+ return this->mutex_;
+ }
+
+ condition_t & condition(void)
+ {
+ return *(this->condition_);
+ }
+
+ // This particular accessor will make things much easier if we
+ // decide that 'int' isn't the correct datatype for value_.
+ // Note that we keep this private and force clients of the class
+ // to use the cast operator to get a copy of the value.
+ value_t & value(void)
+ {
+ return this->value_;
+ }
+};
+
+#endif // CONDITION_H
diff --git a/docs/tutorials/016/Makefile b/docs/tutorials/016/Makefile
new file mode 100644
index 00000000000..65ce0bb1352
--- /dev/null
+++ b/docs/tutorials/016/Makefile
@@ -0,0 +1,74 @@
+
+# $Id$
+
+#----------------------------------------------------------------------------
+# Local macros
+#----------------------------------------------------------------------------
+
+BIN = condition
+
+FILES = Condition_i
+
+BUILD = $(VBIN)
+
+SRC = $(addsuffix .cpp,$(BIN))
+SRC += $(addsuffix .cpp,$(FILES))
+
+#----------------------------------------------------------------------------
+# Include macros and targets
+#----------------------------------------------------------------------------
+
+include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU
+include $(ACE_ROOT)/include/makeinclude/macros.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.common.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.local.GNU
+
+#----------------------------------------------------------------------------
+# Local targets
+#----------------------------------------------------------------------------
+
+rename : #
+ for i in *.cxx ; do \
+ n=`expr "$$i" : "\(.*\).cxx"` ;\
+ mv $$i $$n.cpp ;\
+ done
+
+Indent : #
+ for i in $(SRC) $(HDR) ; do \
+ indent -npsl -l80 -fca -fc1 -cli0 -cdb -ts2 -bl -bli0 < $$i | \
+ sed -e 's/: :/::/g' \
+ -e 's/^.*\(public:\)/\1/' \
+ -e 's/^.*\(protected:\)/\1/' \
+ -e 's/^.*\(private:\)/\1/' \
+ -e 's/:\(public\)/ : \1/' \
+ -e 's/:\(protected\)/ : \1/' \
+ -e 's/:\(private\)/ : \1/' \
+ -e 's/ / /g' \
+ > $$i~ ;\
+ mv $$i~ $$i ;\
+ done
+
+Depend : depend
+ perl ../007/fix.Makefile
+
+.depend : #
+ touch .depend
+
+HTML : #
+ [ -f hdr ] || $(MAKE) UNSHAR
+ perl ../combine *.pre
+
+SHAR : #
+ [ ! -f combine.shar ] || exit 1
+ shar -T hdr bodies *.pre > combine.shar && rm -f hdr bodies *.pre
+
+UNSHAR : #
+ sh combine.shar
+
+#----------------------------------------------------------------------------
+# Dependencies
+#----------------------------------------------------------------------------
+
+include .depend
diff --git a/docs/tutorials/016/combine.shar b/docs/tutorials/016/combine.shar
new file mode 100644
index 00000000000..503f70b83be
--- /dev/null
+++ b/docs/tutorials/016/combine.shar
@@ -0,0 +1,332 @@
+#!/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-10-29 15:09 EST by <jcej@caldera.lads.com>.
+# Source directory was `/scsiA/home/jcej/projects/ACE_wrappers/docs/tutorials/016'.
+#
+# Existing files will *not* be overwritten unless `-c' is specified.
+#
+# This shar contains:
+# length mode name
+# ------ ---------- ------------------------------------------
+# 422 -rw-rw-r-- hdr
+# 50 -rw-rw-r-- bodies
+# 789 -rw-rw-r-- page01.pre
+# 1350 -rw-rw-r-- page02.pre
+# 248 -rw-rw-r-- page03.pre
+# 309 -rw-rw-r-- page04.pre
+# 605 -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 _sh03957; 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 016</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+X
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 016</FONT></B></CENTER>
+X
+<CENTER><B><FONT SIZE=+2>Making ACE_Condition easier to use</FONT></B></CENTER>
+X
+<P>
+<HR WIDTH="100%">
+SHAR_EOF
+ $shar_touch -am 1029153498 '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'
+34600093c989939b7a2a6806f2b18f22 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
+Condition_i.h
+Condition_i.cpp
+condition.cpp
+SHAR_EOF
+ $shar_touch -am 1029153398 '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'
+06c11389b22b88d88110d2338c4dbaaf bodies
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'bodies'`"
+ test 50 -eq "$shar_count" ||
+ $echo 'bodies:' 'original size' '50,' '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 framework has quite a few objects for syncronizing your
+threads and even processes. We've mentioned a few in passing already:
+X ACE_Thread_Mutex and ACE_Barrier for instance.
+<P>
+Another interesting one is the ACE_Condition template. By using an
+ACE_Condition you can have your code wait for an arbitrary condition
+to occur. That condition is "embodied" in a variable of your choice.
+That variable can, in turn, be any data type you wish. This makes
+ACE_Condition much more flexible than a simple mutex, barrier or
+semaphore.
+<P>
+In this tutorial, I'll create a wrapper class around the ACE_Condition
+and the assorted housekeeping items necessary to make it work. I'll
+use a simple integer as the condition variable but keep in mind that
+you can use any data type you want.
+SHAR_EOF
+ $shar_touch -am 1029153198 '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'
+aa9f5774f5415d7a430891e9296bfab0 page01.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page01.pre'`"
+ test 789 -eq "$shar_count" ||
+ $echo 'page01.pre:' 'original size' '789,' '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' &&
+We'll look first at the declaration of the wrapper class.
+<P>
+The way you use ACE_Condition is something like this:
+<UL>
+<LI>First, the setup...
+<UL>
+<LI>Create a variable using your choice of data types
+<LI>Create a mutex that will provide thread-safe access to that
+variable
+<LI>Create an ACE_Condition that uses the mutex
+</UL>
+<P>
+<LI>Waiting for the condition...
+<UL>
+<PRE>
+the_mutex.acquire();
+while( the_variable != some_desired_state_or_value )
+X the_condition.wait();
+the_mutex.release();
+</PRE>
+Note that when <i>the_condition</i> is created, it must be given a
+reference to the mutex. That's because the wait() method will release
+the mutex before waiting and reacquire it after being signaled.
+</UL>
+<P>
+<LI>Setting the condition...
+<UL>
+<PRE>
+the_mutex.acquire();
+the_variable = some_new_value_or_state;
+the_condition.signal() <i>OR</i> the_condition.broadcast()
+</pre>
+</UL>
+</UL>
+<P>
+The problem I have is remembering to setup everything and co-ordinate
+the locking, waiting and signaling. Even if I remember it all
+correctly it just makes my application code more complex than it
+should be.
+<P>
+To help out with that, I've created the class below to encapsulate the
+three elements necessary for the condition to work. I've then added
+methods for manipulation of the condition variable and waiting for the
+condition to occur.
+<HR>
+SHAR_EOF
+ $shar_touch -am 1029191498 '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'
+ccf4d7623038838df6249b5134827402 page02.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page02.pre'`"
+ test 1350 -eq "$shar_count" ||
+ $echo 'page02.pre:' 'original size' '1350,' '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' &&
+Ok, now we'll take a look at the definition of the class. You already
+know how to use an ACE_Condition & it's not really that difficult.
+Still, imagine how much more cluttered your code would be if it had to
+include the mess I've got below!
+<HR>
+SHAR_EOF
+ $shar_touch -am 1029162998 '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'
+51c4ebc7f5c67e072fed8f76bd7be62d page03.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page03.pre'`"
+ test 248 -eq "$shar_count" ||
+ $echo 'page03.pre:' 'original size' '248,' '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' &&
+We finally get to the main() application. I create a simple Task
+derivative that will serve as a baseclass for other objects that test
+specific functions of the Condition class. Notice how easy it is to
+integrate a Condition into the application without keeping track of
+three related member variables.
+<HR>
+SHAR_EOF
+ $shar_touch -am 1029185698 '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'
+b6694ddc18814a64feeb56f46ffd7d17 page04.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pre'`"
+ test 309 -eq "$shar_count" ||
+ $echo 'page04.pre:' 'original size' '309,' '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' &&
+And that's all...
+<P>
+For general use, it would make sense to convert Condition into a
+template and get rid of some of the operators that don't make sense.
+Using an integer as the condition type probably isn't realistic since
+you could just use a semaphore or barrier for that case. Still, the
+Tutorial shows the basics and provides a foundation on which you can
+create a more useful class for your application.
+<P>
+<UL>
+<LI><A HREF="Condition_i.h">Condition_i.h</A>
+<LI><A HREF="Condition_i.cpp">Condition_i.cpp</A>
+<LI><A HREF="condition.cpp">condition.cpp</A>
+<LI><A HREF="Makefile">Makefile</A>
+</UL>
+SHAR_EOF
+ $shar_touch -am 1029192198 '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'
+f63c4bfe37b1fe5785a6af9b204cb0bf page05.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page05.pre'`"
+ test 605 -eq "$shar_count" ||
+ $echo 'page05.pre:' 'original size' '605,' 'current size' "$shar_count!"
+ fi
+fi
+rm -fr _sh03957
+exit 0
diff --git a/docs/tutorials/016/condition.cpp b/docs/tutorials/016/condition.cpp
new file mode 100644
index 00000000000..5ec772a4a7f
--- /dev/null
+++ b/docs/tutorials/016/condition.cpp
@@ -0,0 +1,249 @@
+
+// $Id$
+
+#include "Condition_i.h"
+#include "ace/Task.h"
+
+/* In order to test our Condition we'll derive from ACE_Task<> so that
+ we can have several threads accessing the condition variable
+ together.
+ */
+class Test : public ACE_Task<ACE_NULL_SYNCH>
+{
+public:
+ // Construct the condition variable with an initial value.
+ Test( Condition::value_t _value );
+ ~Test(void);
+
+ // Open the Task with enough threads to make a useful test.
+ int open(void);
+
+protected:
+ // Each thread will do work on the Condition.
+ int svc(void);
+
+ // Override this method to modify the Condition in some way.
+ virtual void modify(void) = 0;
+ // Override this to test the Condition in some way.
+ virtual void test(void) = 0;
+
+ // How many threads to use in the test. This is also used in the
+ // modify() and test() methods of the derivatives.
+ static const int max_threads_;
+
+ // We want to sleep for a random amount of time to simulate
+ // work. The seed is necessary for proper random number generation.
+ ACE_RANDR_TYPE seed_;
+
+ // This is the actual condition variable set.
+ Condition condition_;
+};
+
+// Set the number of threads.
+const int Test::max_threads_ = 5;
+
+// Initialize the condition variable.
+Test::Test( Condition::value_t _value )
+ : condition_(_value)
+{
+ ;
+}
+
+Test::~Test(void)
+{
+ ;
+}
+
+// Seed the random number generator and start the threads.
+int Test::open(void)
+{
+ seed_ = ACE_OS::gettimeofday().usec();
+
+ ACE_OS::srand( seed_ );
+
+ return this->activate(THR_NEW_LWP, max_threads_);
+}
+
+/* Each thread will modify the condition variable in some way and then
+ wait for the condition to be satisfied. The derived classes
+ overload modify() and test() to implement a specific test of the
+ Condition class.
+ */
+int Test::svc(void)
+{
+ // Take a moment before we modify the condition. This will
+ // cause test() in other threads to delay a bit.
+ int stime = ACE_OS::rand_r( seed_ ) % 5;
+ ACE_OS::sleep(abs(stime)+2);
+
+ ACE_DEBUG ((LM_INFO, "(%P|%t|%T)\tTest::svc() befor modify, condition_ is: %d\n", (int)condition_ ));
+
+ // Change the condition variable's value
+ modify();
+
+ ACE_DEBUG ((LM_INFO, "(%P|%t|%T)\tTest::svc() after modify, condition_ is: %d\n", (int)condition_ ));
+
+ // Test for the condition we want
+ test();
+
+ ACE_DEBUG ((LM_INFO, "(%P|%t|%T)\tTest::svc() leaving.\n" ));
+
+ return(0);
+}
+
+/* Test Condition::operator!=()
+ The task's svc() method will increment the condition variable and
+ then wait until the variable's value reaches max_threads_.
+ */
+class Test_ne : public Test
+{
+public:
+ // Initialize the condition variable to zero since we're counting up.
+ Test_ne(void)
+ : Test(0)
+ {
+ ACE_DEBUG ((LM_INFO, "\n(%P|%t|%T)\tTesting condition_ != %d\n", max_threads_));
+ }
+
+ // Increment the variable
+ void modify(void)
+ {
+ ++condition_;
+ }
+
+ // Wait until it equals max_threads_
+ void test(void)
+ {
+ condition_ != max_threads_;
+ }
+};
+
+/* Test Condition::operator>=()
+ Each svc() method will decrement the condition variable and wait
+ until it is less than max_threads_. To do this correctly, we have
+ to be careful where we start the condition variable.
+ */
+class Test_ge : public Test
+{
+public:
+ // For max_threads_ == 5, we will start the condition variable at
+ // the value 9. When the "last" thread decrements it, the value
+ // will be 4 which satisfies the condition.
+ Test_ge(void)
+ : Test(max_threads_*2-1)
+ {
+ ACE_DEBUG ((LM_INFO, "\n(%P|%t|%T)\tTesting condition_ >= %d\n", max_threads_));
+ }
+
+ // Decrement by one...
+ void modify(void)
+ {
+ --condition_;
+ }
+
+ // while( value >= max_threads_ ) wait();
+ void test(void)
+ {
+ condition_ >= max_threads_;
+ }
+};
+
+/* Test Condition::operator<=()
+ This time we will increment the condition until it is greater than
+ max_threads_. Again, we have to be careful where we start the
+ value and how we increment.
+ */
+class Test_le : public Test
+{
+public:
+ // I'm starting the value at 1 so that if we increment by one in
+ // each thread, the "last" thread (of 5) will set the value to
+ // 6. Since I actually increment by 2, we could start somewhat lower.
+ Test_le(void)
+ : Test(1)
+ {
+ ACE_DEBUG ((LM_INFO, "\n(%P|%t|%T)\tTesting condition_ <= %d\n", max_threads_));
+ }
+
+ // Try out Condition::operator+=(int)
+ // This will cause the third thread to satisfy the condition.
+ void modify(void)
+ {
+ condition_ += 2;
+ }
+
+ // while( value <= max_threads_ ) wait();
+ void test(void)
+ {
+ condition_ <= max_threads_;
+ }
+};
+
+/* For our final test, we'll go after Condition::operator=(Condition::Compare)
+ By deriving from Condition::Compare we can perform any arbitrary
+ test on the value of the condition variable.
+ */
+class Test_fo : public Test
+{
+public:
+ // We'll be using operator*=(int) to increment the condition
+ // variable, so we need to start with a non-zero value.
+ Test_fo(void)
+ : Test(1)
+ {
+ ACE_DEBUG ((LM_INFO, "\n(%P|%t|%T)\tTesting condition_ == FunctionObject\n" ));
+ }
+
+ // Double the value for each thread that we have.
+ void modify(void)
+ {
+ condition_ *= 2;
+ }
+
+ /* Derive our CompareFunction and provide the operator() that
+ performs our test. In this case, we'll compare the value to
+ the number 32.
+ */
+ class CompareFunction : public Condition::Compare
+ {
+ public:
+ // When this returns non-zero, the condition test operator
+ // will unblock in each thread.
+ int operator() ( Condition::value_t _value )
+ {
+ return _value == 32;
+ }
+ };
+
+ // Create the CompareFunction and wait for the condition variable
+ // to reach the state we want.
+ void test(void)
+ {
+ CompareFunction compare;
+ condition_ == compare;
+ }
+};
+
+/* In main() we just instantiate each of the four test objects that we
+ created. After open()ing each, we wait() for it's threads to exit.
+ */
+int main(int, char **)
+{
+ Test_ne test_ne;
+ test_ne.open();
+ test_ne.wait();
+
+ Test_ge test_ge;
+ test_ge.open();
+ test_ge.wait();
+
+ Test_le test_le;
+ test_le.open();
+ test_le.wait();
+
+ Test_fo test_fo;
+ test_fo.open();
+ test_fo.wait();
+
+ return(0);
+}
diff --git a/docs/tutorials/016/page01.html b/docs/tutorials/016/page01.html
new file mode 100644
index 00000000000..19b74e2dde8
--- /dev/null
+++ b/docs/tutorials/016/page01.html
@@ -0,0 +1,31 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 016</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 016</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Making ACE_Condition easier to use</FONT></B></CENTER>
+
+<P>
+<HR WIDTH="100%">
+The ACE framework has quite a few objects for syncronizing your
+threads and even processes. We've mentioned a few in passing already:
+ ACE_Thread_Mutex and ACE_Barrier for instance.
+<P>
+Another interesting one is the ACE_Condition template. By using an
+ACE_Condition you can have your code wait for an arbitrary condition
+to occur. That condition is "embodied" in a variable of your choice.
+That variable can, in turn, be any data type you wish. This makes
+ACE_Condition much more flexible than a simple mutex, barrier or
+semaphore.
+<P>
+In this tutorial, I'll create a wrapper class around the ACE_Condition
+and the assorted housekeeping items necessary to make it work. I'll
+use a simple integer as the condition variable but keep in mind that
+you can use any data type you want.
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page02.html">Continue This Tutorial</A>]</CENTER>
diff --git a/docs/tutorials/016/page02.html b/docs/tutorials/016/page02.html
new file mode 100644
index 00000000000..2c323068f54
--- /dev/null
+++ b/docs/tutorials/016/page02.html
@@ -0,0 +1,221 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 016</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 016</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Making ACE_Condition easier to use</FONT></B></CENTER>
+
+<P>
+<HR WIDTH="100%">
+We'll look first at the declaration of the wrapper class.
+<P>
+The way you use ACE_Condition is something like this:
+<UL>
+<LI>First, the setup...
+<UL>
+<LI>Create a variable using your choice of data types
+<LI>Create a mutex that will provide thread-safe access to that
+variable
+<LI>Create an ACE_Condition that uses the mutex
+</UL>
+<P>
+<LI>Waiting for the condition...
+<UL>
+<PRE>
+the_mutex.acquire();
+while( the_variable != some_desired_state_or_value )
+ the_condition.wait();
+the_mutex.release();
+</PRE>
+Note that when <i>the_condition</i> is created, it must be given a
+reference to the mutex. That's because the wait() method will release
+the mutex before waiting and reacquire it after being signaled.
+</UL>
+<P>
+<LI>Setting the condition...
+<UL>
+<PRE>
+the_mutex.acquire();
+the_variable = some_new_value_or_state;
+the_condition.signal() <i>OR</i> the_condition.broadcast()
+</pre>
+</UL>
+</UL>
+<P>
+The problem I have is remembering to setup everything and co-ordinate
+the locking, waiting and signaling. Even if I remember it all
+correctly it just makes my application code more complex than it
+should be.
+<P>
+To help out with that, I've created the class below to encapsulate the
+three elements necessary for the condition to work. I've then added
+methods for manipulation of the condition variable and waiting for the
+condition to occur.
+<HR><PRE>
+
+<font color=red>// $Id$</font>
+
+<font color=blue>#ifndef</font> <font color=purple>CONDITION_H</font>
+<font color=blue>#define</font> <font color=purple>CONDITION_H</font>
+
+<font color=blue>#include</font> "<font color=green>ace/Synch.h</font>"
+
+<font color=red>/** A wrapper for ACE_Condition&lt;>.
+ When you're using an ACE_Condition&lt;> you have to have three things:
+ - Some variable that embodies the condition you're looking for
+ - A mutex to prevent simultaneous access to that variable from different threads
+ - An ACE_Condition&lt;> that enables blocking on state changes in the variable
+ The class I create here will contain those three things. For the
+ actual condition variable I've chosen an integer. You could
+ easily turn this clas into a template parameterized on the
+ condition variable's data type if 'int' isn't what you want.
+ */</font>
+class Condition
+{
+public:
+ <font color=red>// From here on I'll use value_t instead of 'int' to make any</font>
+ <font color=red>// future upgrades easier.</font>
+ typedef int value_t;
+
+ <font color=red>// Initialize the condition variable</font>
+ Condition(value_t _value = 0);
+ ~Condition(void);
+
+ <font color=red>/* I've created a number of arithmetic operators on the class
+ that pass their operation on to the variable. If you turn
+ this into a template then some of these may not be
+ appropriate...
+ For the ones that take a parameter, I've stuck with 'int'
+ instead of 'value_t' to reinforce the fact that you'll need
+ a close look at these if you choose to change the 'value_t'
+ typedef.
+ */</font>
+
+ <font color=red>// Increment & decrement</font>
+ Condition & operator++(void);
+ Condition & operator--(void);
+
+ <font color=red>// Increase & decrease</font>
+ Condition & operator+=(int _inc);
+ Condition & operator-=(int _inc);
+
+ <font color=red>// Just to be complete</font>
+ Condition & operator*=(int _inc);
+ Condition & operator/=(int _inc);
+ Condition & operator%=(int _inc);
+
+ <font color=red>// Set/Reset the condition variable's value</font>
+ Condition & operator=( value_t _value );
+
+ <font color=red>/* These four operators perform the actual waiting. For
+ instance:
+
+ operator!=(int _value)
+
+ is implemented as:
+
+ Guard guard(mutex_)
+ while( value_ != _value )
+ condition_.wait();
+
+ This is the "<font color=green>typical</font>" use for condition mutexes. Each of
+ the operators below behaves this way for their respective
+ comparisions.
+
+ To use one of these in code, you would simply do:
+
+ Condition mycondition;
+ ...
+ <font color=red>// Wait until the condition variable has the value 42</font>
+ mycondition != 42
+ ...
+ */</font>
+
+ <font color=red>// As long as the condition variable is NOT EQUAL TO _value, we wait</font>
+ int operator!=( value_t _value );
+ <font color=red>// As long as the condition variable is EXACTLY EQUAL TO _value, we wait</font>
+ int operator==( value_t _value );
+ <font color=red>// As long as the condition variable is LESS THAN OR EQUAL TO _value, we wait</font>
+ int operator&lt;=( value_t _value );
+ <font color=red>// As long as the condition variable is GREATER THAN OR EQUAL TO _value, we wait</font>
+ int operator>=( value_t _value );
+
+ <font color=red>// Return the value of the condition variable</font>
+ operator value_t (void);
+
+ <font color=red>/* In addition to the four ways of waiting above, I've also
+ create a method that will invoke a function object for each
+ iteration of the while() loop.
+ Derive yourself an object from <font color=#008888>Condition::Compare</font> and
+ overload operator()(value_t) to take advantage of this. Have
+ the function return non-zero when you consider the condition
+ to be met.
+ */</font>
+ class Compare
+ {
+ public:
+ virtual int operator() ( value_t _value ) = 0;
+ };
+
+ <font color=red>/* Wait on the condition until _compare(value) returns
+ non-zero. This is a little odd since we're not really testing
+ equality. Just be sure that _compare(value_) will return
+ non-zero when you consider the condition to be met.
+ */</font>
+ int operator==( Compare & _compare );
+
+private:
+ <font color=red>// Prevent copy construction and assignment.</font>
+ Condition( const Condition & _condition );
+ Condition & operator= ( const Condition & _condition );
+
+ <font color=red>/* Typedefs make things easier to change later.
+ ACE_Condition_Thread_Mutex is used as a shorthand for
+ ACE_Condition&lt;ACE_Thread_Mutex> and also because it may
+ provide optimizations we can use.
+ */</font>
+ typedef ACE_Thread_Mutex mutex_t;
+ typedef ACE_Condition_Thread_Mutex condition_t;
+ typedef ACE_Guard&lt;mutex_t> guard_t;
+
+ <font color=red>// The mutex that keeps the data save</font>
+ mutex_t mutex_;
+
+ <font color=red>// The condition mutex that makes waiting on the condition</font>
+ <font color=red>// easier.</font>
+ condition_t * condition_;
+
+ <font color=red>// The acutal variable that embodies the condition we're</font>
+ <font color=red>// waiting for.</font>
+ value_t value_;
+
+ <font color=red>// Accessors for the two mutexes.</font>
+ mutex_t & mutex(void)
+ {
+ return this->mutex_;
+ }
+
+ condition_t & condition(void)
+ {
+ return *(this->condition_);
+ }
+
+ <font color=red>// This particular accessor will make things much easier if we </font>
+ <font color=red>// decide that 'int' isn't the correct datatype for value_.</font>
+ <font color=red>// Note that we keep this private and force clients of the class</font>
+ <font color=red>// to use the cast operator to get a copy of the value.</font>
+ value_t & value(void)
+ {
+ return this->value_;
+ }
+};
+
+<font color=blue>#endif</font> <font color=red>// CONDITION_H</font>
+</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/016/page03.html b/docs/tutorials/016/page03.html
new file mode 100644
index 00000000000..a0bfb9b9be5
--- /dev/null
+++ b/docs/tutorials/016/page03.html
@@ -0,0 +1,224 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 016</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 016</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Making ACE_Condition easier to use</FONT></B></CENTER>
+
+<P>
+<HR WIDTH="100%">
+Ok, now we'll take a look at the definition of the class. You already
+know how to use an ACE_Condition & it's not really that difficult.
+Still, imagine how much more cluttered your code would be if it had to
+include the mess I've got below!
+<HR>
+<PRE>
+
+<font color=red>// $Id$</font>
+
+<font color=red>// Get or declaration</font>
+<font color=blue>#include</font> "<font color=green>Condition_i.h</font>"
+
+<font color=red>/* Initialize the condition variable and create the condition mutex.
+ Since I don't have any guarantees on the order of member variable
+ initialization, I have to new the condition mutex instead of
+ simply constructing it.
+ */</font>
+<font color=#008888>Condition::Condition</font>(value_t _value)
+ : value_(_value)
+{
+ condition_ = new condition_t( this->mutex() );
+}
+
+<font color=#008888>Condition::~Condition</font>(void)
+{
+ <font color=red>// Be sure we don't have a memeory leak</font>
+ delete condition_;
+}
+
+<font color=red>/* The cast operator is the easiest way to return a copy of the value
+ to clients of the class. It also allows us to use a private method
+ for getting a reference to the value when we need to modify it.
+ */</font>
+<font color=#008888>Condition::operator</font> value_t (void)
+{
+ <font color=red>// Place a guard around the variable so that it won't change as</font>
+ <font color=red>// we're copying it back to the client.</font>
+ guard_t guard(mutex_);
+ return value();
+}
+
+<font color=red>/* Traditional prefix increment operator.
+ We place a guard around the operation so that we don't collide with
+ any other threads. After the modification, we broadcast() a
+ condition change to any waiting threads. You can also use signal()
+ but that will only tell one thread about the change. If that
+ thread, in turn, invokes signal() then all threads will eventually
+ find out. I just thought it would be easier to use broadcast() and
+ be done with it.
+ */</font>
+Condition & <font color=#008888>Condition::operator</font>++ (void)
+{
+ guard_t guard(mutex_);
+
+ ++value();
+
+ condition().broadcast();
+
+ return *this;
+}
+
+<font color=red>/* The remaining operators all follow the same pattern that we have
+ above. They only differ in the modification they make to the value().
+ */</font>
+
+Condition & <font color=#008888>Condition::operator</font>-- (void)
+{
+ guard_t guard(mutex_);
+
+ --value();
+
+ condition().broadcast();
+
+ return *this;
+}
+
+Condition & <font color=#008888>Condition::operator</font>+= (int _inc)
+{
+ guard_t guard(mutex_);
+
+ value() += _inc;
+
+ condition().broadcast();
+
+ return *this;
+}
+
+Condition & <font color=#008888>Condition::operator</font>-= (int _inc)
+{
+ guard_t guard(mutex_);
+
+ value() -= _inc;
+
+ condition().broadcast();
+
+ return *this;
+}
+
+Condition & <font color=#008888>Condition::operator</font>*= (int _inc)
+{
+ guard_t guard(mutex_);
+
+ value() *= _inc;
+
+ condition().broadcast();
+
+ return *this;
+}
+
+Condition & <font color=#008888>Condition::operator</font>/= (int _inc)
+{
+ guard_t guard(mutex_);
+
+ value() /= _inc;
+
+ condition().broadcast();
+
+ return *this;
+}
+
+Condition & <font color=#008888>Condition::operator</font>%= (int _inc)
+{
+ guard_t guard(mutex_);
+
+ value() %= _inc;
+
+ condition().broadcast();
+
+ return *this;
+}
+
+Condition & <font color=#008888>Condition::operator</font>= ( value_t _value )
+{
+ guard_t guard(mutex_);
+
+ value() = _value;
+
+ condition().broadcast();
+
+ return *this;
+}
+
+<font color=red>/* Now we get into the comparison area.
+ Each one follows the pattern we've already established for
+ waiters.
+ */</font>
+
+<font color=red>/*
+ We begin with an equality operator that expects a function object.
+ In the while() test we pass a copy of the value to the function
+ object for evaluation. The object can then do any comparision it
+ wants to check for a desired condition. When the function object
+ returns non-zero, the condition is met and we leave.
+ */</font>
+int <font color=#008888>Condition::operator</font>== ( Condition::Compare & _compare )
+{
+ guard_t guard(mutex_);
+
+ while( ! _compare(this->value()) )
+ condition().wait();
+
+ return 0;
+}
+
+<font color=red>// As long as the variable equals _value, we wait...</font>
+int <font color=#008888>Condition::operator</font>== ( value_t _value )
+{
+ guard_t guard(mutex_);
+
+ while( value() == _value )
+ condition().wait();
+
+ return 0;
+}
+
+<font color=red>// As long as the variable is not equal to _value, we wait...</font>
+int <font color=#008888>Condition::operator</font>!= ( value_t _value )
+{
+ guard_t guard(mutex_);
+
+ while( value() != _value )
+ condition().wait();
+
+ return 0;
+}
+
+<font color=red>// As long as the variable is less than or equal to _value, we wait...</font>
+int <font color=#008888>Condition::operator</font>&lt;= ( value_t _value )
+{
+ guard_t guard(mutex_);
+
+ while( value() &lt;= _value )
+ condition().wait();
+
+ return 0;
+}
+
+<font color=red>// As long as the variable is greater than or equal to _value, we wait...</font>
+int <font color=#008888>Condition::operator</font>>= ( value_t _value )
+{
+ guard_t guard(mutex_);
+
+ while( value() >= _value )
+ condition().wait();
+
+ return 0;
+}
+</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/016/page04.html b/docs/tutorials/016/page04.html
new file mode 100644
index 00000000000..b01d96fe23e
--- /dev/null
+++ b/docs/tutorials/016/page04.html
@@ -0,0 +1,272 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 016</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 016</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Making ACE_Condition easier to use</FONT></B></CENTER>
+
+<P>
+<HR WIDTH="100%">
+We finally get to the main() application. I create a simple Task
+derivative that will serve as a baseclass for other objects that test
+specific functions of the Condition class. Notice how easy it is to
+integrate a Condition into the application without keeping track of
+three related member variables.
+<HR><PRE>
+
+<font color=red>// $Id$</font>
+
+<font color=blue>#include</font> "<font color=green>Condition_i.h</font>"
+<font color=blue>#include</font> "<font color=green>ace/Task.h</font>"
+
+<font color=red>/* In order to test our Condition we'll derive from ACE_Task&lt;> so that
+ we can have several threads accessing the condition variable
+ together.
+ */</font>
+class Test : public ACE_Task&lt;ACE_NULL_SYNCH>
+{
+public:
+ <font color=red>// Construct the condition variable with an initial value.</font>
+ Test( <font color=#008888>Condition::value_t</font> _value );
+ ~Test(void);
+
+ <font color=red>// Open the Task with enough threads to make a useful test.</font>
+ int open(void);
+
+protected:
+ <font color=red>// Each thread will do work on the Condition.</font>
+ int svc(void);
+
+ <font color=red>// Override this method to modify the Condition in some way.</font>
+ virtual void modify(void) = 0;
+ <font color=red>// Override this to test the Condition in some way.</font>
+ virtual void test(void) = 0;
+
+ <font color=red>// How many threads to use in the test. This is also used in the</font>
+ <font color=red>// modify() and test() methods of the derivatives.</font>
+ static const int max_threads_;
+
+ <font color=red>// We want to sleep for a random amount of time to simulate</font>
+ <font color=red>// work. The seed is necessary for proper random number generation.</font>
+ ACE_RANDR_TYPE seed_;
+
+ <font color=red>// This is the actual condition variable set.</font>
+ Condition condition_;
+};
+
+<font color=red>// Set the number of threads.</font>
+const int <font color=#008888>Test::max_threads_</font> = 5;
+
+<font color=red>// Initialize the condition variable.</font>
+<font color=#008888>Test::Test</font>( Condition::value_t _value )
+ : condition_(_value)
+{
+ ;
+}
+
+<font color=#008888>Test::~Test</font>(void)
+{
+ ;
+}
+
+<font color=red>// Seed the random number generator and start the threads.</font>
+int <font color=#008888>Test::open</font>(void)
+{
+ seed_ = <font color=#008888>ACE_OS::gettimeofday</font>().usec();
+
+ <font color=#008888>ACE_OS::srand</font>( seed_ );
+
+ return this->activate(THR_NEW_LWP, max_threads_);
+}
+
+<font color=red>/* Each thread will modify the condition variable in some way and then
+ wait for the condition to be satisfied. The derived classes
+ overload modify() and test() to implement a specific test of the
+ Condition class.
+ */</font>
+int <font color=#008888>Test::svc</font>(void)
+{
+ <font color=red>// Take a moment before we modify the condition. This will</font>
+ <font color=red>// cause test() in other threads to delay a bit.</font>
+ int stime = <font color=#008888>ACE_OS::rand_r</font>( seed_ ) % 5;
+ <font color=#008888>ACE_OS::sleep</font>(abs(stime)+2);
+
+ ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t|%T)\<font color=#008888>tTest::svc</font>() befor modify, condition_ is: %d\n</font>", (int)condition_ ));
+
+ <font color=red>// Change the condition variable's value</font>
+ modify();
+
+ ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t|%T)\<font color=#008888>tTest::svc</font>() after modify, condition_ is: %d\n</font>", (int)condition_ ));
+
+ <font color=red>// Test for the condition we want</font>
+ test();
+
+ ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t|%T)\<font color=#008888>tTest::svc</font>() leaving.\n</font>" ));
+
+ return(0);
+}
+
+<font color=red>/* Test <font color=#008888>Condition::operator</font>!=()
+ The task's svc() method will increment the condition variable and
+ then wait until the variable's value reaches max_threads_.
+ */</font>
+class Test_ne : public Test
+{
+public:
+ <font color=red>// Initialize the condition variable to zero since we're counting up.</font>
+ Test_ne(void)
+ : Test(0)
+ {
+ ACE_DEBUG ((LM_INFO, "<font color=green>\n(%P|%t|%T)\tTesting condition_ != %d\n</font>", max_threads_));
+ }
+
+ <font color=red>// Increment the variable</font>
+ void modify(void)
+ {
+ ++condition_;
+ }
+
+ <font color=red>// Wait until it equals max_threads_</font>
+ void test(void)
+ {
+ condition_ != max_threads_;
+ }
+};
+
+<font color=red>/* Test <font color=#008888>Condition::operator</font>>=()
+ Each svc() method will decrement the condition variable and wait
+ until it is less than max_threads_. To do this correctly, we have
+ to be careful where we start the condition variable.
+ */</font>
+class Test_ge : public Test
+{
+public:
+ <font color=red>// For max_threads_ == 5, we will start the condition variable at </font>
+ <font color=red>// the value 9. When the "<font color=green>last</font>" thread decrements it, the value</font>
+ <font color=red>// will be 4 which satisfies the condition.</font>
+ Test_ge(void)
+ : Test(max_threads_*2-1)
+ {
+ ACE_DEBUG ((LM_INFO, "<font color=green>\n(%P|%t|%T)\tTesting condition_ >= %d\n</font>", max_threads_));
+ }
+
+ <font color=red>// Decrement by one...</font>
+ void modify(void)
+ {
+ --condition_;
+ }
+
+ <font color=red>// while( value >= max_threads_ ) wait();</font>
+ void test(void)
+ {
+ condition_ >= max_threads_;
+ }
+};
+
+<font color=red>/* Test <font color=#008888>Condition::operator</font>&lt;=()
+ This time we will increment the condition until it is greater than
+ max_threads_. Again, we have to be careful where we start the
+ value and how we increment.
+ */</font>
+class Test_le : public Test
+{
+public:
+ <font color=red>// I'm starting the value at 1 so that if we increment by one in</font>
+ <font color=red>// each thread, the "<font color=green>last</font>" thread (of 5) will set the value to</font>
+ <font color=red>// 6. Since I actually increment by 2, we could start somewhat lower.</font>
+ Test_le(void)
+ : Test(1)
+ {
+ ACE_DEBUG ((LM_INFO, "<font color=green>\n(%P|%t|%T)\tTesting condition_ &lt;= %d\n</font>", max_threads_));
+ }
+
+ <font color=red>// Try out <font color=#008888>Condition::operator</font>+=(int)</font>
+ <font color=red>// This will cause the third thread to satisfy the condition.</font>
+ void modify(void)
+ {
+ condition_ += 2;
+ }
+
+ <font color=red>// while( value &lt;= max_threads_ ) wait();</font>
+ void test(void)
+ {
+ condition_ &lt;= max_threads_;
+ }
+};
+
+<font color=red>/* For our final test, we'll go after <font color=#008888>Condition::operator</font>=(Condition::Compare)
+ By deriving from <font color=#008888>Condition::Compare</font> we can perform any arbitrary
+ test on the value of the condition variable.
+ */</font>
+class Test_fo : public Test
+{
+public:
+ <font color=red>// We'll be using operator*=(int) to increment the condition</font>
+ <font color=red>// variable, so we need to start with a non-zero value.</font>
+ Test_fo(void)
+ : Test(1)
+ {
+ ACE_DEBUG ((LM_INFO, "<font color=green>\n(%P|%t|%T)\tTesting condition_ == FunctionObject\n</font>" ));
+ }
+
+ <font color=red>// Double the value for each thread that we have.</font>
+ void modify(void)
+ {
+ condition_ *= 2;
+ }
+
+ <font color=red>/* Derive our CompareFunction and provide the operator() that
+ performs our test. In this case, we'll compare the value to
+ the number 32.
+ */</font>
+ class CompareFunction : public <font color=#008888>Condition::Compare</font>
+ {
+ public:
+ <font color=red>// When this returns non-zero, the condition test operator</font>
+ <font color=red>// will unblock in each thread.</font>
+ int operator() ( <font color=#008888>Condition::value_t</font> _value )
+ {
+ return _value == 32;
+ }
+ };
+
+ <font color=red>// Create the CompareFunction and wait for the condition variable </font>
+ <font color=red>// to reach the state we want.</font>
+ void test(void)
+ {
+ CompareFunction compare;
+ condition_ == compare;
+ }
+};
+
+<font color=red>/* In main() we just instantiate each of the four test objects that we
+ created. After open()ing each, we wait() for it's threads to exit.
+ */</font>
+int main(int, char **)
+{
+ Test_ne test_ne;
+ test_ne.open();
+ test_ne.wait();
+
+ Test_ge test_ge;
+ test_ge.open();
+ test_ge.wait();
+
+ Test_le test_le;
+ test_le.open();
+ test_le.wait();
+
+ Test_fo test_fo;
+ test_fo.open();
+ test_fo.wait();
+
+ 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/016/page05.html b/docs/tutorials/016/page05.html
new file mode 100644
index 00000000000..5cffcb2d459
--- /dev/null
+++ b/docs/tutorials/016/page05.html
@@ -0,0 +1,30 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 016</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 016</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Making ACE_Condition easier to use</FONT></B></CENTER>
+
+<P>
+<HR WIDTH="100%">
+And that's all...
+<P>
+For general use, it would make sense to convert Condition into a
+template and get rid of some of the operators that don't make sense.
+Using an integer as the condition type probably isn't realistic since
+you could just use a semaphore or barrier for that case. Still, the
+Tutorial shows the basics and provides a foundation on which you can
+create a more useful class for your application.
+<P>
+<UL>
+<LI><A HREF="Condition_i.h">Condition_i.h</A>
+<LI><A HREF="Condition_i.cpp">Condition_i.cpp</A>
+<LI><A HREF="condition.cpp">condition.cpp</A>
+<LI><A HREF="Makefile">Makefile</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 bbdd6e350e7..f9ec9b48f29 100644
--- a/docs/tutorials/index.html
+++ b/docs/tutorials/index.html
@@ -106,6 +106,20 @@ Paddling down (and up) the ACE_Stream</H4>
<A HREF="015/page01.html">A certain amount of Protocol is required!</A></LI>
</OL>
+
+<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>
+-->
+</OL>
+
<HR>
<P>Back to the <A