/* As usual, our open() will create one or more threads where we'll do the interesting work. */ int Test::open(void * _unused) { ACE_UNUSED_ARG(_unused); // 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_, 1); }
/* svc() will execute in each thread & do a few things with the Barrier we have. */ int Test::svc(void) { // Say hello to everyone first. ACE_DEBUG(( LM_INFO, "(%P|%t|%T) Created\n" )); // Increment and save the "tcount" value. We'll use it in // just a moment... int me = ++tcount_; // Wait for all initial threads to get to this point before we // go any further. This is standard barrier usage... barrier_.wait(); // Setup our random number generator. ACE_Time_Value now(ACE_OS::gettimeofday()); ACE_RANDR_TYPE seed = now.usec(); ACE_OS::srand(seed); int delay; // We'll arbitrarily choose the first activated thread to be // the controller. After it sleeps a few seconds, it will add // five threads. if( me == 1 ) { // Sleep from 1 to 10 seconds so that some of the other // threads will be into their for() loop. delay = ACE_OS::rand_r(seed)%10; ACE_OS::sleep(abs(delay)+1); // Make ourselves the barrier owner so that we can change // the number of threads. This should be done with care... barrier_.owner( ACE_OS::thr_self() ); // Add 5 threads to the barrier and then activate() to // make them real. Notice the third parameter to // activate(). Without this parameter, the threads won't // be created. if( barrier_.threads(threads_+5) == 0 ) { this->activate(THR_NEW_LWP,5,1); } } // This for() loop represents an "infinite" work loop in an // application. The theory is that the threads are dividing up // some work but need to "recalibrate" if more threads are // added. I'll just do five iterations so that the test // doesn't run forever. int i; for( i = 0 ; i < 5 ; ++i ) { // The sleep() represents time doing work. delay = ACE_OS::rand_r(seed)%7; ACE_OS::sleep(abs(delay)+1); ACE_DEBUG(( LM_INFO, "(%P|%t|%T)\tThread %.2d of %.2d iteration %.2d\n", me, threads_, i )); // If the local threads_ variable doesn't match the number // in the barrier, then the controller must have changed // the thread count. We'll wait() for everyone and then // recalibrate ourselves before continuing. if( this->threads_ != barrier_.threads() ) { ACE_DEBUG(( LM_INFO, "(%P|%t|%T) Waiting for thread count to increase to %d from %d\n", barrier_.threads(), this->threads_ )); // Wait for all our sibling threads... barrier_.wait(); // Set our local variable so that we don't come here again. this->threads_ = barrier_.threads(); // Recalibration can be anything you want. At this // point, we know that all of the threads are synch'd // and ready to go. } } // Re-synch all of the threads before they exit. This isn't // really necessary but I like to do it. barrier_.done(); return(0); }