Boost logo

Boost Users :

Subject: Re: [Boost-users] Race condition with Boost::Thread
From: Craig Henderson (cdm.henderson_at_[hidden])
Date: 2009-07-29 10:45:27


2009/7/29 Craig Henderson <cdm.henderson_at_[hidden]>

>
>
> 2009/7/29 Rob Yull <ryull_at_[hidden]>
>
>> I’ve been writing a thread pool class as kind of an experiment with
>> boost.threads, boost.bind, and boost.function. The code below is the worker
>> thread, that will eventually pull jobs from a queue, execute them, then look
>> and see if there is another job in the queue. I think I’ve got an
>> interesting race condition. The problem I’m having is when the class goes
>> out of scope. I’m getting an access violation from the run() member
>> function (which is function being run by m_Thread). Right now, run() is
>> just entering and leaving (no actual queue checking). By the time run() is
>> getting executed, the class is starting to execute the destructor. I
>> thought that having the join() call in the destructor should allow the
>> thread to finish before the class data is destroyed. In Visual Studio
>> 2005’s debugger, when it is getting to run(), it looks like the object has
>> already been destroyed (this = 0x7fffffff), so the access violation is
>> coming from the assignment to the m_Running member variable. If I take out
>> the assignment, and run the debug, when it is entering run(), the this
>> pointer is still showing as invalid, but the function completes and ends up
>> back at the join() in the destructor, where the this pointer in the
>> destructor is valid again. So as far as the destructor seems to be
>> conserned, the class hasn’t been destroyed yet, but as far as the member
>> class is, it has been destroyed already.
>>
>>
>>
>> If I do pad some instructions/time before the class goes out of scope,
>> run() executes just fine (this pointer is valid). I have also tried moving
>> the creation of m_Thread outside of the constructor to a separate member
>> function call, but the result is the same.
>>
> [sorry for the partial post earlier]

Hi Rob,

The WorkerThread object is going out of scope before the run() is executed
in the secondary thread. You need to synchronise the startup/shutdown down.
I suggest you move the m_Running=true; into the run() [the thread isn't
running until run() is called, afterall], and in the dtor, wait for the
thread to start before calling join.

class WorkerThread
{
public:
      typedef boost::function<void ()> JobType;

      WorkerThread()
      {
            m_Thread = boost::thread(boost::bind(&WorkerThread::run,
boost::ref(this)));
       }

      ~WorkerThread()
      {
            while (!m_Running)
                ;
            m_Thread.join();
            m_Running = false;
      }

      const bool isRunning() const
      {
            return m_Running;
      }

private:
      volatile bool m_Running;
      boost::thread m_Thread;

      void run()
      {
            m_Running = true;
            BOOST_ASSERT(isRunning());
      }

private:
      WorkerThread(const WorkerThread& rhs);
      WorkerThread& operator = (const WorkerThread& rhs);
};

Regards
-- Craig



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