C Board  

Go Back   C Board > General Programming Boards > C++ Programming

Reply
 
LinkBack Thread Tools Display Modes
Old 10-11-2004, 10:19 PM   #1
Disturbed Boy
 
gustavosserra's Avatar
 
Join Date: Apr 2003
Posts: 244
Thread creation on virtual functions

Hello everyone.
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*)
}
Tnx any help!
__________________
Nothing more to tell about me...
Happy day =)
gustavosserra is offline   Reply With Quote
Old 10-11-2004, 10:27 PM   #2
Registered User
 
Codeplug's Avatar
 
Join Date: Mar 2003
Posts: 3,903
Lets put english aside and talk code!

This post shows how to implement thread objects that can run class member functions in the context of the thread.

- Been wait'n to post this one

gg
Codeplug is offline   Reply With Quote
Old 10-11-2004, 10:38 PM   #3
Registered User
 
Codeplug's Avatar
 
Join Date: Mar 2003
Posts: 3,903
And for the benefit of all readers, don't forget http://www.function-pointer.org/

gg
Codeplug is offline   Reply With Quote
Old 10-12-2004, 02:09 PM   #4
Disturbed Boy
 
gustavosserra's Avatar
 
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   Reply With Quote
Old 10-13-2004, 11:14 AM   #5
Registered User
 
Codeplug's Avatar
 
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
Output:
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   Reply With Quote
Old 10-13-2004, 11:44 AM   #6
Cat without Hat
 
CornedBee's Avatar
 
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   Reply With Quote
Old 10-13-2004, 12:44 PM   #7
and the hat of marbles
 
Sang-drax's Avatar
 
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
  }
};
Although boost come quite close
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   Reply With Quote
Old 10-13-2004, 01:27 PM   #8
Cat without Hat
 
CornedBee's Avatar
 
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   Reply With Quote
Old 10-13-2004, 01:43 PM   #9
Registered User
 
Codeplug's Avatar
 
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   Reply With Quote
Old 10-13-2004, 02:13 PM   #10
Cat without Hat
 
CornedBee's Avatar
 
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   Reply With Quote
Old 10-13-2004, 11:20 PM   #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   Reply With Quote
Old 10-14-2004, 07:28 AM   #12
Disturbed Boy
 
gustavosserra's Avatar
 
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   Reply With Quote
Old 10-14-2004, 07:53 AM   #13
Registered User
 
Codeplug's Avatar
 
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   Reply With Quote
Old 10-14-2004, 08:03 AM   #14
Disturbed Boy
 
gustavosserra's Avatar
 
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   Reply With Quote
Reply

Thread Tools
Display Modes

Forum Jump

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


All times are GMT -6. The time now is 02:33 AM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22