![]() |
| | #1 |
| Disturbed Boy Join Date: Apr 2003
Posts: 244
| Thread creation on virtual functions I need help making (as everyone does) a game. There is a base class that implements some basic attibutes for moving objects. There are other derived classes that change the behavior of the movement. The problem is that the constructor creates a thread to update the position (and speed) of the object. Each class has its own method to update, hence, the method is virtual. I know that I can create one huge thread and call the virtual method on an array of the objects, but I am curious. I created a pointer to a member function, but it is not of type (void*)(*)(void*), as thread needs. Please, ask me to explain again if my english is too bad.Here a small example: Code: //header.h
class Base{
public:
Base();
virtual void* update(void*)=0;
private:
// does not matter
};
class Creature : public Base{
public:
Creature();
void* update(void*)
private:
// who cares...
};
Code: //implementation.cpp
Creature::Creature()
{
void*(Creature::*f)(void*) = &Creature::update;
// will create thread here, but type of "f" is not void*(*)(void*)
}
__________________ Nothing more to tell about me... Happy day =) |
| gustavosserra is offline | |
| | #3 |
| Registered User Join Date: Mar 2003
Posts: 3,903
| |
| Codeplug is offline | |
| | #4 |
| Disturbed Boy Join Date: Apr 2003
Posts: 244
| Thanks I have made this "model" (I was unable to test it, problems with SDL ). What do you think of it?Code: //header.h
class Base{
public:
/* "p" is the data that the thread will run on,
the parameter can be stored in class, and never
be used as a paramater to the thread ;) */
Base(void* p);
/* "callback" function of the thread, receives a base class */
static int call_update(void*);
/* thread function itself */
virtual int update(void*)=0;
void join(){ SDL_WaitThread(thread, NULL); }
private:
/* pointer that will hold the data */
void* data;
SDL_Thread* thread;
};
class Creature : public Base{
public:
Creature();
int update(void*);
private:
// who cares...
};
class Mage : public Base{
public:
Mage(int power);
int update(void*);
private:
int myPower;
};
Code: //implementation.cpp
Base::Base(void* p)
{
data = p;
thread = SDL_CreateThread(Base::call_update, this);
}
int Base::call_update(void* base_class)
{
Base* b = static_cast<Base*>(base_class);
b->update(b->data);
}
/* We don't use any parameter in Creature,
so the pointer can be NULL */
Creature::Creature()
: Base(NULL){}
int Creature::update(void*)
{
for(int i=0;i<3;i++)
cout << "I am a Creature counting... " << i << endl;
}
Mage::Mage(int power)
: Base(&myPower){
myPower = power;
}
int Mage::update(void*)
{
cout << "I am a mage with power: " << myPower << endl;
}
__________________ Nothing more to tell about me... Happy day =) |
| gustavosserra is offline | |
| | #5 |
| Registered User Join Date: Mar 2003
Posts: 3,903
| I wouldn't use inheritance to bring in thread functionality. For example, which statement below makes more sense: - Creature "is a" thread (inheritance) - Creature "has a" thread (aggregation) In order to use aggregation, you need a thread object. The link I posted shows how to implement thread objects that can call class member functions in the context of the thread. If the member function being called is virtual, polymorphism will apply as usual. Below is a simple thread object implementation that uses SDL threads. Code: #include<iostream>
using namespace std;
#include "SDL.h"
#include "SDL_thread.h"
#ifdef _MSC_VER // VC++ compiler?
# pragma comment(lib, "SDL.lib")
# pragma comment(lib, "SDLmain.lib")
#endif
// call STL_Init() in constructor and SDL_Quit() in destructor
struct sdlInitializer
{
const bool bIsInitialized;
explicit sdlInitializer(Uint32 flags)
: bIsInitialized(SDL_Init(flags) == 0) {}
~sdlInitializer() {if (bIsInitialized) SDL_Quit();}
};//sdlInitializer
// SDL thread that runs in the context of a member function
template<class OBJ_T>
class sdlThread_Mfn
{
// type of this class instance
typedef sdlThread_Mfn<OBJ_T> ThisType;
// pointer to OBJ_T member function type
typedef int (OBJ_T::*MfnThreadFunc_t)();
SDL_Thread *m_thread; // returned by SDL_CreateThread()
OBJ_T *m_thread_obj; // object instance to run thread in
MfnThreadFunc_t m_pmfn;// member function to run within m_thread_obj
// helper function used by static thread function
int call_member_func()
{
return (m_thread_obj->*m_pmfn)();
}//call_member_func
// thread function called by SDL_CreateThread()
static int thread_func(void *data)
{
return static_cast<ThisType*>(data)->call_member_func();
}//thread_func
public:
// we need an object instance and a pointer to a member function
// of that object
explicit sdlThread_Mfn(OBJ_T *obj, MfnThreadFunc_t thread_func)
: m_thread(0), m_thread_obj(obj), m_pmfn(thread_func) {}
bool start()
{
m_thread = SDL_CreateThread(thread_func, this);
return m_thread != 0;
}//start
int join()
{
int status = 0;
SDL_WaitThread(m_thread, &status);
return status;
}//join
private:
sdlThread_Mfn(); // no default construction
sdlThread_Mfn(const sdlThread_Mfn&); // no copies
sdlThread_Mfn& operator=(const sdlThread_Mfn&); // no assignment
};//sdlThread_Mfn
class Base
{
typedef sdlThread_Mfn<Base> MemberFuncThread;
MemberFuncThread *m_thread; // Base class "has a" thread
public:
Base() {m_thread = new MemberFuncThread(this, &Base::thread_func);}
~Base() {delete m_thread;}
bool run_thread() {return m_thread->start();}
int join_thread() {return m_thread->join();}
virtual int thread_func()
{
cout << "Base::thread_func" << endl;
return 1;
}//thread_func
};//Base
class Derived : public Base
{
public:
virtual int thread_func()
{
cout << "Derived::thread_func" << endl;
return 2;
}//thread_func
};//Derived
int SDL_main(int argc, char *argv[])
{
sdlInitializer sdli(SDL_INIT_EVENTTHREAD);
if (!sdli.bIsInitialized)
{
cerr << "Failed to initialize SDL : " << SDL_GetError() << endl;
return 1;
}//if
Base b;
if (b.run_thread())
b.join_thread();
else
cerr << "Failed to run Base thread : " << SDL_GetError() << endl;
Derived d;
if (d.run_thread())
d.join_thread();
else
cerr << "Failed to run Derived thread : " << SDL_GetError() << endl;
return 0;
}//SDL_main
Base::thread_func Derived::thread_func Let me know if anyone needs clarification on the code. Pointer to member function semantics can be looked up at http://www.function-pointer.org/. >> I was unable to test it, problems with SDL I had some issues with SDL initially. If you're still having problems then post them here (including OS, compiler, compiler/linker errors/warnings). gg |
| Codeplug is offline | |
| | #6 |
| Cat without Hat Join Date: Apr 2003
Posts: 8,492
| You could also use Boost.Threads: http://www.boost.org/ http://www.boost.org/libs/thread/doc/index.html It has the advantage that it's far easier to use member functions as thread starters.
__________________ All the buzzt! CornedBee"There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code." - Flon's Law |
| CornedBee is offline | |
| | #7 |
| and the hat of marbles Join Date: May 2002 Location: Lund, Sweden
Posts: 2,041
| Hmm, I've only looked at boost's thread library just now, but I think I like the Java approach better, where a thread is created by creating a new class and inheriting from a base thread class. Code: //This is how I think a thread library should be
//constructed in C++
class MyThread:
public Thread;
{
void run()
{
//Thread function
}
};
Code: class MyThread:
public boost::thread
{
MyThread():
boost::thread(run)
{
}
void run()
{
//Thread function
}
};
[ontopic] gustavosserra, you wouldn't want every game object in its own thread. Instead, make a single game thread that loops the list of objects and calls your abstract update() method. [/ontopic]
__________________ Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling |
| Sang-drax is offline | |
| | #8 |
| Cat without Hat Join Date: Apr 2003
Posts: 8,492
| For Java, I like implementing Runnable, I don't like inheriting from Thread. Somehow it doesn't feel right for me. I like the way Boost approaches it.
__________________ All the buzzt! CornedBee"There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code." - Flon's Law |
| CornedBee is offline | |
| | #9 |
| Registered User Join Date: Mar 2003
Posts: 3,903
| I usually choose flexibility over ease-of-use. While we're on the topic of design, I highly recomend Design Paterns. If you don't already have it, read what you can and see if it tickles your interest. gg |
| Codeplug is offline | |
| | #10 |
| Cat without Hat Join Date: Apr 2003
Posts: 8,492
| Currently reading Modern C++ Design. That's a yummy book
__________________ All the buzzt! CornedBee"There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code." - Flon's Law |
| CornedBee is offline | |
| | #11 |
| Registered User Join Date: Oct 2003
Posts: 28
| Hi gustavosserra, Try this concept in your code and let me know whether it works... Code: #include <iostream>
#include <pthread.h>
using namespace std;
extern "C" void *thread1(void *IncommingArg);
class MainClass
{
public:
MainClass()
{
pthread_create(NULL, NULL, thread1, this);
// Here I have used "pthread_create" function to create a thread
// where "thread1" is the function to be called
// and "this" is the parameter to be passed to the function.
// I have no idea of SDL. Hope you can do it.
}
void memberFunction()
{
// Function, which you want to run as a thread
// Signature of this function can be anything you want
}
};
extern "C" void *thread1(void *IncommingArg)
{
((MainClass *)IncommingArg)->memberFunction();
return NULL;
}
int main()
{
MainClass obj;
return 0;
}
__________________ Success is a two word story, "WORK" works. |
| pratip is offline | |
| | #12 |
| Disturbed Boy Join Date: Apr 2003
Posts: 244
| Pratip, I am using Windows. The argument of Codeplug sounds very good to me, I agree that a creature has a thread. Inheritance seems a little dirty in this case. Sang-drax, I will use a vector *and* individual threads, because, a ship for example, needs an acceleration effect, which I implement with sleep concept. Indeed vector and virtual method is very suited for this case. Codeplug, thanks for the code, mind if I use it? ![]() For all of you, my thanks.
__________________ Nothing more to tell about me... Happy day =) |
| gustavosserra is offline | |
| | #13 |
| Registered User Join Date: Mar 2003
Posts: 3,903
| Anyone is more than welcome to use it. ![]() >> I will use a vector *and* individual threads Sang-drax has a very valid point on not using a thread for every game object (assuming that you will have more than 20 game objects as some point). Context switching from one thread to another can be a relatively expensive operation. For example, 4 threads each controlling 25 objects is a lot better than 100 threads controlling 1 object. Grouping your objects into functional thread groups, like those that need an "acceleration effect", is a good place to start. gg |
| Codeplug is offline | |
| | #14 |
| Disturbed Boy Join Date: Apr 2003
Posts: 244
| Yes, I was thinking in context switching. My browser closed and my post was lost, so I didn't write it again, too lazy . I can't use a thread per object, imagine a super powerfull ship shooting at high rate, each shot creating a thread will crash everthing . Thanks everyone, again.
__________________ Nothing more to tell about me... Happy day =) |
| gustavosserra is offline | |
![]() |
| Thread Tools | |
| Display Modes | |
|
Similar Threads | ||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| C thread functions? | audinue | C Programming | 3 | 07-08-2008 07:47 AM |
| i need a good example of virtual functions | Anddos | C++ Programming | 10 | 02-15-2006 11:48 AM |
| concerning virtual functions | shadovv | C++ Programming | 4 | 10-25-2005 10:22 PM |
| Virtual Functions | guda | C++ Programming | 3 | 11-16-2004 04:13 PM |
| virtual templated functions | ygfperson | C++ Programming | 5 | 08-15-2003 11:01 PM |