run threads of class member function in c++

14,572

Solution 1

Seriously, use std::thread:

class CLASS
{
public:
    void A();
private:
    void B(your args go here);
};

void CLASS::A()
{
    std::thread t(&CLASS::B, this, your args go here);
    // when done
    t.join();
    // or
    t.detach();
}

Explanation

Your code doesn't compile because CreateThread is a C API, expecting a non-member C function as a callback. In order to call a non-static member function of a C++ class, the caller needs to know about this pointer and how to correctly use it. Since WinAPI clearly doesn't have this and doesn't expect a member function pointer, this cannot possibly work. Your compiler catches this and reports it as a type mismatch error.

This is where the lpParameter of CreateThread comes into play. It allows you to pass this through that parameter. However it doesn't change the fact that CreateThread doesn't know how to call C++ member functions. Therefore it's your responsibility to wrap it in a static function that will do the member function call:

class CLASS
{
public:
    void A();
private:
    DWORD B();
    static DWORD s_B(LPVOID);
};

DWORD CLASS::s_B(LPVOID that) {
    return ((CLASS*)that)->B();
}

void CLASS::A() {
    CreateThread(NULL, 0, s_B, this, 0, NULL);
}

This is what @Nawaz does in their answer, except in a slightly more general way.

Even though this approach works, it clearly has downsides:

  • It's verbose.
  • It's non portable.
  • You need to pass your original args through different means (e.g. through a member of your class).

std::thread already does all that for you.

Solution 2

You've to define your callback function as static function if it's member function!


Better design : define a reusable class!

From my previous answer: (with little modification)

Even better would be to define a reusable class with pure virtual function run() to be implemented by the derived thread classes. Here is how it should be designed:

//runnable is reusable class. All thread classes must derive from it! 
class runnable
{
public:
    virtual ~runnable() {}
    static DWORD WINAPI run_thread(LPVOID args)
    {
        runnable *prunnable = static_cast<runnable*>(args);
        return prunnable->run();
    }
 protected:
    virtual DWORD run() = 0; //derived class must implement this!
};

class Thread : public runnable //derived from runnable!
{
public:
    void newthread()
    {
        CreateThread(NULL, 0, &runnable::run_thread, this, 0, NULL);
    }
protected:
    DWORD run() //implementing the virtual function!
    {
         /*.....your thread execution code.....*/
    }
}

Solution 3

You have to make that member function static.

The problem here is that every non-static member function has an implicit this parameter and that's in fact what the compiler is trying to tell you - your nin-static member function has signature different from the one you expected.

Also see this answer to a closely related question.

Share:
14,572
superscalar
Author by

superscalar

Updated on June 09, 2022

Comments

  • superscalar
    superscalar almost 2 years

    As the title says. The following is my code skeleton.

    class CLASS
    {
    public:
        void A();
    private:
        DWORD WINAPI B(LPVOID);
    };
    
    void CLASS::A()
    {
        DWORD (WINAPI CLASS::*thread)(LPVOID) = &CLASS::B;
        ...
        CreateThread(NULL, 0, thread, &arg, 0, NULL);
        ...
    }
    

    the function B needs CLASS's member variables.
    But I've got an error code when I compiled this.
    It's " can't convert argument 3 from 'DWORD (__stdcall CLASS::* )(LPVOID)' to 'LPTHREAD_START_ROUTINE' " or something like that.
    I don't know if it is the same in the english environment.

    can anybody help please?

  • bdonlan
    bdonlan over 13 years
    And before the OP starts getting any clever ideas - non-static class member function pointers are weird. Not only are the calling conventions different from a simple func(classname *this, ...), the pointer representation is weird - in some cases class member function pointers can end up being 2x the size of a normal function pointer, so don't even think about forcing the cast :)
  • usta
    usta over 13 years
    +1. Yes, definitely go with std::/boost::thread. Moreover, you don't even need bind: boost::thread t(&CLASS::B, this, your args if any go here);. As simple as that.
  • Puppy
    Puppy over 13 years
    I would use a template, rather than run-time inheritance. But the general idea is correct.
  • Nawaz
    Nawaz over 13 years
    @DeadMG : yeah.. that would be a little fast... just didn't come to mind when I wrote this...
  • Puppy
    Puppy over 13 years
    @Nawaz: You should always think CRTP first, and then run-time inheritance.
  • Nawaz
    Nawaz over 13 years
    @DeadMG : Yup. I realized that now. :-)
  • Maxim Egorushkin
    Maxim Egorushkin over 13 years
    It is a bit old-fashioned and awkward design to have to derive a class and override a function to run a thread. Better use boost::thread or a similar mechanism that accepts a functor as a thread function and does not require deriving anything.