Thread: Thread creation on virtual functions

  1. #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 =)

  2. #2
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    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

  3. #3
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    And for the benefit of all readers, don't forget http://www.function-pointer.org/

    gg

  4. #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 =)

  5. #5
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    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

  6. #6
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    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

  7. #7
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    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

  8. #8
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    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

  9. #9
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    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

  10. #10
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    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

  11. #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.

  12. #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 =)

  13. #13
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    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

  14. #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 =)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. C thread functions?
    By audinue in forum C Programming
    Replies: 3
    Last Post: 07-08-2008, 07:47 AM
  2. i need a good example of virtual functions
    By Anddos in forum C++ Programming
    Replies: 10
    Last Post: 02-15-2006, 11:48 AM
  3. concerning virtual functions
    By shadovv in forum C++ Programming
    Replies: 4
    Last Post: 10-25-2005, 10:22 PM
  4. Virtual Functions
    By guda in forum C++ Programming
    Replies: 3
    Last Post: 11-16-2004, 04:13 PM
  5. virtual templated functions
    By ygfperson in forum C++ Programming
    Replies: 5
    Last Post: 08-15-2003, 11:01 PM