0

I'm currently working on a SDL_Project that includes Timers. A SDL_Timer can have a callback function, and since my timer is located in a class this callbackfunction is a static member function to which I pass "this" via void*-argument.

But the class has also another member variable, which is a pointer. But as soon as I call the callbackfunction, these pointers aren't valid anymore. Which kinda makes sense, I suppose, since the static function is called in another thread.

Is there a way to get around this problem? I'm not very familiar with Multithreading, so I have no idea what to look for.

This is a basic representation of what I'm doing, though this examples works just fine, since it's all in one thread, if my theory is right.

//A is just an interface so that B can hold a pointer to it
class A
{
public:
    virtual int get() = 0;
};

class C
{
public:
    C(){};
    C(A* parent_arg)
    {
        parent = parent_arg;
    }

    void (*fptr)(C* sender) = nullptr;

    static void callback(void* param)
    {
        //In my actual program, me has lost its parent pointer
        C* me = (C*)param; 
        me->fptr(me);
    };

    //In my actual code, this function is from a SDL_Timer and
    //runs in another thread
    void Go()
    {
        callback(this);
    }

    A* parent = nullptr;
};


class B : A
{
public:
    B()
    {
        c.parent = this;
    };

    virtual int get() { return myint; };
    C c;
private:
    int myint = 5;
};

void myfun (C* sender)
{
    std::cout << sender->parent->get() << "\n";
};

int _tmain(int argc, _TCHAR* argv[])
{

    B b;

    b.c.fptr = myfun;
    b.c.Go();

    int test;
    std::cin >> test;
    return 0;
}

Edit:

Here is a little more information about what I do with C and B after they're created and how they are implemented in the actual program. All of the classes involved are copy constructable. And the member variable c in B is in a boost::stable_vector. Since for other tasks this all works fine, I assume that my copy constructors and assignment operators are ok. If I check the values of me in the callback, it turns out that me itself has still all its values in place, except the pointers.

Edit2:

I found the problem. I didn't update the parent pointer when I copied B object. Thank you all for your help.

  • What about binding the member function to it's actual instance, when creating the thread? – πάντα ῥεῖ Oct 05 '14 at 16:05
  • Did you mean like this? `std::function t = std::bind(this->callback, std::placeholders::_1, std::placeholders::_2); l_timer = SDL_AddTimer(l_delay, t, this);` ? Here I get an "unable to convert from SDL_Callback to std::function" error. – LordOfThunder123 Oct 05 '14 at 16:09
  • Does the `SDL_Callback` allow for a user defined extra argument of `void*`? Otherwise chances are low, to get this bound to a particular class instances, whose member function should be called from within the thread. – πάντα ῥεῖ Oct 05 '14 at 16:15
  • SDL_Callback expects the callback function to be `Uint32 callback (Uint32, void*)` Did you mean an additional void*? Then no, but couldn't I use a pair? If so, what should I do with it? – LordOfThunder123 Oct 05 '14 at 16:19
  • OK, the best way to handle this, is to have a static class method, that expects a pointer to `class C`. Then pass a pointer to a valid instance of `C` in the `void argument`. In the callback function, cast the `void*` value to `C*`, call `C::mystatic_callback()` and pass the `C*` as parameter. Then you're able to call any of `C`'s class member functions. – πάντα ῥεῖ Oct 05 '14 at 16:24
  • Taking a closer look, you already seem to do correctly what I proposed. I'd guess your problems of the _lost_ `A* parent;` values appear elsewhere. S.th. [rule-of-three](http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three) related most probably. – πάντα ῥεῖ Oct 05 '14 at 16:28
  • I've gone through it already before I posted, but couldn't find an obvious problem. I guess I have to familiarize myself a little bit more with the pointer/class/member stuff and constructors. Thank you for your help! – LordOfThunder123 Oct 05 '14 at 18:20
  • Can you show what you do with B after you set up the callback? – Surt Oct 05 '14 at 21:42

2 Answers2

0

You provided too little information to answer you with certainty. Most likely the object b gets destroyed (probably from the thread it was created in) before callback is called from another thread.

Add a destructor with some logging to class B. Add some logging in the beginning of C::callback() as well, this will give you a hint what's happening. And also, add a virtual destructor to A, it's crucial in case you have something like A* a = new B(); delete a;.

Anton Savin
  • 40,838
  • 8
  • 54
  • 90
0

If you can't detect issues through manual code review use valgrind memcheck/helgrind to help you out with detecting any potential memory corruption issues.

sanjayk79
  • 542
  • 3
  • 15