c++ , pthread and static callbacks. “this” returns

2019-09-02 14:29发布

问题:

This question already has an answer here:

  • c++ , pthread and static callbacks. “this” returns a pointer to the base class inctead of the derived one (part 2) 1 answer

I am using as basis this cpp thread class. This I use as a base class for threads. Note that in my case Thread::main() is a virtual function (unlike in the link). So I basically use:

class Thread {
public:
    virtual void main()
    {
        cout << "This should not be run once derived and redefined." << endl;
    }

    void run()
    {
        pthread_create(&thread, 0, &callback, this);
    }

    pthread_t thread;
}; // class Thread


void* callback(void* obj)
{
    static_cast<Thread*>(obj)->main();
    return(0);
} // callback

Then I create a derived class and re-define the myThreadedClass::main() member to actually do something meaningful.

Finally, I instantiate the myThreadedClass object from other classes or my main function call as follows:

main(int argc, char** argv){
    myThreadedClass thr;
    thr.run();

    //do other stuff
}

This works fine; The callback function gets a pointer to the derived class instantiation, so the myThreadedClass::main() gets executed.

However, I now try to create a different derived class class otherThreadClass : public Thread. Again I re-define my otherThreadClass::main() , but now I have a member function in the derived class which (unlike before) calls Thread::run().

class otherThreadClass : public Thread{
public:
    writeToDiskAsync(string& str){
       prepareString(str);

       //spawn a thread to carry the write without blocking execution
       run();
    }
};

in this case from my main function I do

main(int argc, char** argv){
    otherThreadClass thr;
    thr.writeToDiskAsync(aString);

    //do other stuff
}

The problem in this case is that the callback function gets a pointer to the Thread class and the Thread::main() ends up being executed instead of the otherThreadClass::main().

I tried passing a pointer to the instantiated myThreadedClass object during instantiation (using initialisation lists and an altered call to Thread::run(void* instance)) as follows

//in main function
otherThreadClass thr(&thr);

//in class
otherThreadClass::otherThreadClass(otherThreadClass* ptr):instancePtr(ptr)
{}

otherThreadClass::writeToDiskAsync(string& str)
{
    //do stuff
    run(instancePtr);
}

//and finally

Thread::run(void* parentObj)
{
    pthread_create(&thread, 0, &callback, parentObj);
}

but it does not work. And I think this is probably not a nice way to do it anyway. So what can I do to let the callback function get apointer to the derived class instance instead of the base class ?

thank you

回答1:

If you will try to call a function using base class ptr , everytime base class version gets called as long as function is not virtual . so simpler solution to your problem would be to make main virtual as below :

  #include <iostream>
#include<pthread.h>
#include<unistd.h?
using namespace std;
void* callback(void* obj);
class Thread {
public:
  virtual  int main()
    {
        cout << "Hi there Base class" << endl;
        return(0);
    }

    void run()
    {
        pthread_create(&thread, 0, &callback, this);
    }

    pthread_t thread;
};

class otherThreadClass : public Thread{
public:
virtual  int main()
    {
        cout << "Hi there other class" << endl;
        return(0);
    }


   void writeToDiskAsync(string str){


       //spawn a thread to carry the write without blocking execution
       run();
    }
};

class Thread;
void* callback(void* obj)
{
    static_cast<Thread*>(obj)->main();
    return(0);
} // callback


int main() {
    // your code goes here
    otherThreadClass thr;
    thr.writeToDiskAsync(string("aS"));
sleep(10);//it is neccessary as main thread can exit before .
    return 0;
}
output : Hi there other class

Whereas if main is not virtual , it will always call base class version of main as you are calling through a base class ptr (static binding will happen )