Boost logo

Boost Users :

From: Mark Sizer (yg-boost-users_at_[hidden])
Date: 2003-07-31 17:07:30


>>That being said, I use the method you describe. Just make sure your
>>object doesn't go out of scope or get deleted.
>>
>
>
> Yes. I'd already got this far. :-)
>
> At the moment we use a system that involves inheriting from an object
> which creates the thread and overriding the method that is run in the
> thread. We have a variable number of threads in this particular
> application, which are stored in a container. This is easy because there
> is only one object to store.
>
> After looking at the boost thread stuff the only idea I've had so far is
> to store a structure in the container which has two members. One is the
> thread object the other is the thread. However, this idea doesn't feel
> right at the moment and I'm going to have to give it some more thought.
> Any suggestions would be greatly appreciated.
>

Unless you need to join the threads later, you can just ignore the
boost::thread object. I let some of mine just go out of scope and
nothing bad has happened, yet.

I don't really like the thread objects because they're not comparable or
copyable. I get why (there have been long discussions here about it),
but it's still annoying. If you need to hold onto them, one easy way is
to use a map with your objects as the key and a pointer to the thread
object as the value. This means your threads shouldn't be on the stack.
But since they're not copyable, you can't put them in the map directly.

ThreadGroups are good for this, too. If you start all the threads in the
same group, the group holds onto them. You can join the entire group in
one call. It's quite convenient.

My "doing" class that the thread runs is Handle/Body (it was and I
didn't want to change it, I'm used to the patter). Therefore, I just do
this to ramp them up:

static void ReceiverBody::StartThreads( int iThreadCount)
{
     for (int i = 0; i< iThreadCount; i++)
     {
       // handle on stack, but body is on allocated on heap
       Receiver recvr;
       // let the group hold onto the thread objects, I don't care
       _tgReceiveThreads.create_thread( recvr );
     }
}

Where _tgReceiveThreads is a static boost::thread_group.

Note that the thread entry-point functor is the handle, Receiver, not
the body, ReceiverBody.

void Receiver::operator()()
{
     _pBody->Receive();
}

To shut them all down:

static ReceiverBody::StopThreads()
{
     { boost::mutex::scoped_lock lockStop( _mutexStop );
       _bStop = true;
     }
     _tgReceiveThreads.join_all();
}

Where the threading loop inside is:

void ReceiverBody::Receive()
{
     bool bDone = bShuttingDown();

     while (!bDone)
     {
       try
       {

       }
       catch ( errors )
       {
       }

       bDone = bShuttingDown();
     }
}
with this helper method:

static bool ReceiverBody::bShuttingDown()
{
     bool bLocalStop = false;
     { boost::mutex::scoped_lock lockStop( _mutexStop );
       bLocalStop = _bStop;
     }

     return bLocalStop;
}
Note that this can't be const, even though it sort-of is. It modifies
the mutex, even though that doesn't matter to the logical state of the
object.

Yes, I know this could be much shorter:
static bool ReceiverBody::bShuttingDown()
{
     { boost::mutex::scoped_lock lockStop( _mutexStop );
       return _bStop;
     }
}
I don't like methods that leave out of the middle. The original is also
easier to debug because you can set breakpoints that don't depend on the
mutex state. However, that's another topic (see comp.lang.c++.moderated
for an EXTENSIVE discussion on exiting methods - that's a very
contentious bunch).

_bStop is a static bool member.
_mutexStop is a static boost::mutex member.

Works great.

- 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