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.
I know debugging multithreaded apps can
be difficult. Is there right out something I’m doing wrong here or
making some kind of bad assumpion about the execution of run()?
#include <boost/config.hpp>
#include <boost/thread.hpp>
#include <boost/functional.hpp>
class WorkerThread
{
public:
typedef boost::function<void ()> JobType;
WorkerThread()
{
m_Thread
= boost::thread(boost::bind(&WorkerThread::run, boost::ref(this)));
m_Running
= true;
}
~WorkerThread()
{
m_Thread.join();
}
const bool
isRunning() const
{
return m_Running;
}
private:
volatile bool m_Running;
boost::thread m_Thread;
void run()
{
m_Running
= false; // Access
violation here
}
private:
WorkerThread(const WorkerThread& rhs);
WorkerThread& operator = (const
WorkerThread& rhs);
};
int main()
{
WorkerThread wt; // new
thread should start executing here
return 0;
}
-Rob Yull