Boost logo

Boost Users :

From: Mark Sizer (boost_at_[hidden])
Date: 2003-10-14 12:48:52


Huck finn wrote:

> Hi, I need a way to find out if the threads that I created are done or
> not. I'm creating a somekind of thread_group that must clean the threads
> that have ended from the vector that keeps the threads within.
>
>
> void function ()
> {}
>
> void main ()
> {
> boost::thread thrd1(&function);
>
> //I'd need a function here to tell me that the thread has ended...
> if(thread1.IsDone())
> {
> ...
> }
> }

Unless your thread does something VERY short, that's probably not what
you want anyway. It would look more like:

int main() // note the "int"
{
   boost::thread thread1(&function); // note variable names match now

   while ( true )
   {
     if ( thread1.IsDone() )
     {
       // cleanup
       break;
     }
   }
}

In which case you can do this:

int main()
{
   boost::thread thread1(&function );
   thread1.join();

   // won't get here until the thread ends
}

This, of course, has the obvious problem of blocking until the thread is
complete. Sometimes that's a good thing; sometimes not.

My solution:

class worker
{
   public:
     worker() :
       _mutexDone(),
       _bDone(false) // in most cases this is race condition safe
                     // but not all, you may have to lock it
       {
       }

     bool isDone() const
       {
         boost::mutex::scoped_lock lockDone(_mutexDone);
         return _bDone;
       }

     void doWork()
       {
         // do whatever
         markDone();
       }

   private:
     void markDone()
       {
         boost::mutex::scoped_lock lockDone(_mutexDene);
         _bDone = true;
       }

     mutable boost::mutex _mutexDone;
     bool _bDone;
};

You get the idea. You can create a graceful shutdown interface with
another pair of methods with the public/private reversed (public to set
the shutdown flag, private to check it).

Now, the problem is that this will get copied if you try to use it
directly, which is why there is no operator(). You'll need to wrap this
in some sort of handle class with the appropriate operators. I happen to
have one handy that I just re-use.

The important bit is to make sure copying is OK and add the operator()
calls worker::doWork(). Assuming a handle class that does reference
counting, etc..

class threadworker : public handle
{
   public:
     threadworker* pbodyWorker() const
       {
         assert( handle.body != NULL );
         return dynamic_cast<threadworker*>(handle.body);
       }

     threadworker() :
       handle( new worker )
       {
       }

     threadworker( const threadworker& rkOther ) :
       handle( rkOther )
       {
       }

     void operator()
       {
         pbodyWorker()->doWork();
       }

     bool isDone()
       {
         return pbodyWorker()->isDone();
       }

   private:
     // disallow this one
     threadworker& operator=( const threadworker& );
};

There's probably a more "boosty" way to create handles than this, but
since I've got the infrastructure and it's a very common pattern in my
code base (written LONG before boost and STL came along), it fits for me.

Anyway, now you've got your asynchronous isDone() check and you're
checking the same object that the thread is running, not a copy of it.

HTH (much longer than I intended),
- Mark


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net