• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Mercenarey

Boost::thread - problems with inheritance

11 posts in this topic

I have made a class to launch threads like this:


#include <boost/thread.hpp>
class BaseThreadObject
{
protected:
//---------- Protected Properties -----------------
boost::thread* m_thread;
//------------ Protected Methods ------------------
public:
//-- Constructors, Destructor & Support Methods ---
BaseThreadObject();
virtual ~BaseThreadObject();

void Startup();
void Shutdown();
//-------- Get's --------------------------
//-------- Set's --------------------------
//---------- Public Methods -----------------------
void operator()();

virtual void ThreadMain() = 0;
};

// ------------------------------------------------
// ------------------------------------------------
// ------------------------------------------------
void BaseThreadObject::operator()()
{
ThreadMain();
}

// ------------------------------------------------
// ------------------------------------------------
// ------------------------------------------------
void BaseThreadObject::Startup()
{
m_thread = new boost::thread(boost::ref(*this));
// m_thread = new boost::thread(*this);
}

// ------------------------------------------------
// ------------------------------------------------
// ------------------------------------------------
void BaseThreadObject::Shutdown()
{
m_thread->join();
}

// ------------------------------------------------
// ------------------------------------------------
// ------------------------------------------------
void BaseThreadObject::ThreadMain()
{
// whatever
}





The Startup launches the thread with the class as a ref, to prevent it from being copied (boost takes 10(!!) copies when launching). Also, I hoped that with a ref, that I could have preserved the inheritance, so I could call derived classes through virtual methods.

However, when I call a virtual method, even if it is implemented in the base class, like the operator()() calls ThreadMain() (which I hoped I could then freely derive for new classes, while preserving basic threading functionality in this baseclass alone), it will fail with this message:
"Unhandled exception at 0x00000000 in [prog-name].exe: 0xC0000005: Access violation reading location 0x00000000"

I have similar problems when I don't use the ref and allows it to copy. It will only copy the class, that is directly inputted, not the classes it derives from.

Is there any way I can create a class like this with boost, that retains an inheritance structure?
0

Share this post


Link to post
Share on other sites
I don't know why you're having type problems, but what I do is have the class contain a "work()" function.

Then go;

typedef shared_ptr<boost::thread> ThrP;
ThrP thr;

thr=ThrP(new boost::thread(boost::bind(&CMyClass::work,this)));

I don't care then if boost starts copying the bind output about the place, because it's copying a dinky class and not my class.
0

Share this post


Link to post
Share on other sites
I'm suspecting that no matter how much you try to cheat by using boost::ref to pass a functor to boost::thread's constructor, internally it will still at some point make a copy of the functor, and when that happens, it won't have a clue that you're really passing a derived thread object and not a BaseThreadObject. Hence it will store a copy of the BaseThreadObject part of the class instance you're passing it. The result -> slicing (google it).


I suggest the following.



struct MyFunctor
{
BaseThreadObject* m_ptrToThreadObject;

MyFunctor( BaseThreadObject* ptrToThreadObject ) : m_ptrToThreadObject( ptrToThreadObject ) {}

void operator () ()
{
m_ptrToThreadObject->ThreadMain();
}
};

void BaseThreadObject::Startup()
{
m_thread = new boost::thread( MyFunctor( this ) );
}




But beware that you may run into object life time issues if your BaseThreadObject instance gets deleted while your thread is still running (and hence potentially accessing your BaseThreadObject instance).
0

Share this post


Link to post
Share on other sites
Red Ant, good suggestion.

I tried it, and put a breakpoint in MyFunctor::operator()(), to inspect the values. m_ptrToThreadObject had the same address as the BaseThreadObject, but the values inside BaseThreadObject were wrong (uninitialized). The same was true when another breakpoint stopped in BaseThreadObject::ThreadMain() (which I implemented directly in BaseThreadObject, to not have inheritance make it even more complex).

How is this possible? Since there is only one class, how can it be sliced?
Im completely lost at what is going on with boost::thread...

Edit:
Just for the record, I created a test variable (an integer) and gave it a value in Startup(), before launching. It is this value that does not show up in the threaded version.
0

Share this post


Link to post
Share on other sites
I've just skimmed over, but wouldn't

new boost::thread(boost::bind(&BaseThreadObject::operator(), this));

be a safe way to address all your issues?

*edit*
And just out of curiosity, why are you storing the boost::thread instance on the heap? You don't need to initialize a boost::thread in its constructor, so the following will work as well (and you don't have to call delete in your destructor):

class Whatever
{
boost::thread m_thread;

Whatever()
{
// some code
m_thread = boost::thread(boost::bind(&Whatever::operator(), this));
}
};


Another thing that bugs me (although this may never be an issue in real cases) is that what if operator() gets called BEFORE the derrived class is constructed. I am not sure but I think the overloaded thread main function pointer will not be written into the vtable until the construction of the derrived class. Therefore your code might not work in those cases.

*edit2*
I just saw this got suggested before. If this doesn't work for you, then the issue is something else. We use boost::thread at work in exactly that way and it works perfectly.
0

Share this post


Link to post
Share on other sites
I don't know what happened yesterday, but when I tested the code again today with a fresh machine and compilation, it worked as it is supposed to, with Red Ant's implementation.

So now it works perfectly!

SiS-Shadowman, Bind() is a possibility as well, if you don't like the operator()(), and creating thread on the heap is also a possibility. Personally I prefer to create it dynamically, I feel I have more control over it, as I can call Shutdown() and have it destroyed, instead of relying on the destructor (maybe I want to reuse the object and use Shutdown() to reset the object for a new Startup()?).

I have tested it with inheritance as well, and it works fine.

Final implementation:

// ------------------------------------------------
// ------------------------------------------------
class BaseThreadObject
{
// ----------------------------------------
// Red Ant's version modified to my code
// standard. Inlined as implementation is
// irrelevant to outsiders.
// ----------------------------------------
struct BaseThreadObjectFunctor
{
BaseThreadObject* m_basethreadobject;
BaseThreadObjectFunctor(BaseThreadObject* a_basethreadobject);

void operator()();
};
protected:
//------------ Protected Properties ---------------
int m_testdata;
boost::thread* m_thread;
MyFunctor* m_myfunctor;
//------------ Protected Methods ------------------
public:
//-- Constructors, Destructor & Support Methods ---
BaseThreadObject();
virtual ~BaseThreadObject();

void Startup();
void Shutdown();
//---- Get's ----------------------
//---- Set's ----------------------
//-------------- Public Methods -------------------
virtual void ThreadMain();
};


// ------------------------------------------------
// ------------------------------------------------
class TestThreadObject : public BaseThreadObject
{
protected:
//------------ Protected Properties ---------------
//------------ Protected Methods ------------------
public:
//-- Constructors, Destructor & Support Methods ---
TestThreadObject();
virtual ~TestThreadObject();
//---- Get's ----------------------
//---- Set's ----------------------
//-------------- Public Methods -------------------
virtual void ThreadMain();
};


// ------------------------------------------------
// ------------------------------------------------
// ------------------------------------------------
BaseThreadObject::BaseThreadObjectFunctor::BaseThreadObjectFunctor(BaseThreadObject* a_basethreadobject) : m_basethreadobject(a_basethreadobject)
{
}

// ------------------------------------------------
// ------------------------------------------------
// ------------------------------------------------
void BaseThreadObject::BaseThreadObjectFunctor::operator()()
{
m_basethreadobject->ThreadMain();
}

// ------------------------------------------------
// ------------------------------------------------
// ------------------------------------------------
void BaseThreadObject::Startup()
{
m_testdata = 11;

m_myfunctor = new MyFunctor(this);
m_thread = new boost::thread(boost::ref(*m_myfunctor));
}

// ------------------------------------------------
// ------------------------------------------------
// ------------------------------------------------
void BaseThreadObject::Shutdown()
{
m_thread->join();
}

// ------------------------------------------------
// ------------------------------------------------
// ------------------------------------------------
void BaseThreadObject::ThreadMain()
{
// m_testdata will correctly be 11 in the thrown thread
int dd = m_testdata;
}

// ------------------------------------------------
// ------------------------------------------------
// ------------------------------------------------
void TestThreadObject::ThreadMain()
{
// m_testdata will correctly be 11 in the thrown thread - also here
// in the derived thread
int dd = BaseThreadObject::m_testdata;
}






[Edited by - Mercenarey on June 25, 2010 9:19:56 AM]
0

Share this post


Link to post
Share on other sites
Quote:
Original post by SiS-Shadowman

*edit*
And just out of curiosity, why are you storing the boost::thread instance on the heap? You don't need to initialize a boost::thread in its constructor, so the following will work as well (and you don't have to call delete in your destructor):

class Whatever
{
boost::thread m_thread;

Whatever()
{
// some code
m_thread = boost::thread(boost::bind(&Whatever::operator(), this));
}
};



Does that actually work? Does boost::thread really provide the proper assigment / copying semantics for that to work?
0

Share this post


Link to post
Share on other sites
Yes. As far as I know this does a simple swap.
Documentation

I stumpled upon this by accident when I created the thread in an initializer list, and it started modifying my class before the constructor was finished.
0

Share this post


Link to post
Share on other sites
Thanks alot for the help guys. This has been hands-down my most severe problem to date. Took me two full days of work to finally crack.

GameDev to the rescue every time :)
0

Share this post


Link to post
Share on other sites
Quote:
Original post by SiS-Shadowman
Yes. As far as I know this does a simple swap.
Documentation


Well, that's why I'm asking. I've looked at the documentation and didn't find anything in there that says operator = invokes the swap() method. If it really does, then it appears to be an undocumented feature, which means it's probably best not to rely on it.

0

Share this post


Link to post
Share on other sites
Quote:
Original post by Red Ant
I'm suspecting that no matter how much you try to cheat by using boost::ref to pass a functor to boost::thread's constructor, internally it will still at some point make a copy of the functor, and when that happens, it won't have a clue that you're really passing a derived thread object and not a BaseThreadObject. Hence it will store a copy of the BaseThreadObject part of the class instance you're passing it. The result -> slicing (google it).


I suggest the following.


*** Source Snippet Removed ***

But beware that you may run into object life time issues if your BaseThreadObject instance gets deleted while your thread is still running (and hence potentially accessing your BaseThreadObject instance).


Thanks you for the post.

__________________
Watch Grown Ups Online Free
0

Share this post


Link to post
Share on other sites

You guys are genius !!! Was struggling with getting my thread encapsulation done properly, that functor method in a struct of a base class did the job !!!

 

thanks

0

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.
Sign in to follow this  
Followers 0