<!-- 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<> so that we can have several threads accessing the condition variable together. */</font> class Test : public ACE_Task<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><=() 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_ <= %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 <= max_threads_ ) wait();</font> void test(void) { condition_ <= 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>