Sophie

Sophie

distrib > Mandriva > 10.0-com > i586 > by-pkgid > 21280410b6ea906d791d7a12afae2579 > files > 286

libace5-doc-5.4-2mdk.i586.rpm

<!-- page04.html,v 1.8 2000/03/19 20:09:32 jcej Exp -->
<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>// page04.html,v 1.8 2000/03/19 20:09:32 jcej Exp</font>

<font color=blue>#include</font> "<font color=green>Condition_i.h</font>"
<font color=blue>#include</font> "<A HREF="../../../ace/Task.h">ace/Task.h</A>"

<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( int _max_threads, <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>
    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>// Initialize the condition variable.</font>
<font color=#008888>Test::Test</font>( int _max_threads, Condition::value_t _value )
        : max_threads_(_max_threads), 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_ );

        <font color=red>// This is not a place where we want to use THR_DETACHED.</font>
        <font color=red>// We're going to be waiting for our threads and if we detach</font>
        <font color=red>// them, we'll loose track and horrible things will happen.</font>
    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( int _max_threads )
            : Test(_max_threads,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( int _max_threads )
            : Test(_max_threads,_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( int _max_threads )
            : Test( _max_threads, 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( int _max_threads )
            : Test( _max_threads, 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>
         <font color=red>// Note that 32 was chosen because 2**5 == 32.  That is, the</font>
         <font color=red>// fifth thread will modify() the value to 32.</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(5);
    test_ne.open();
    test_ne.wait();

    Test_ge test_ge(5);
    test_ge.open();
    test_ge.wait();

    Test_le test_le(5);
    test_le.open();
    test_le.wait();

    Test_fo test_fo(5);
    test_fo.open();
    test_fo.wait();

    return(0);
}
</PRE>
<P><HR WIDTH="100%">
<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page05.html">Continue This Tutorial</A>]</CENTER>