【问题标题】:Member function in another thread loses its classes pointers另一个线程中的成员函数丢失其类指针
【发布时间】:2014-10-05 16:02:48
【问题描述】:

我目前正在开发一个包含计时器的 SDL_Project。 SDL_Timer 可以有一个回调函数,因为我的计时器位于一个类中,所以这个回调函数是一个静态成员函数,我通过 void*-argument 将“this”传递给它。

但是该类还有另一个成员变量,它是一个指针。但是一旦我调用回调函数,这些指针就不再有效。我想这有点道理,因为静态函数是在另一个线程中调用的。

有没有办法解决这个问题?我对多线程不是很熟悉,所以我不知道要寻找什么。

这是我正在做的事情的基本表示,虽然这个例子工作得很好,因为如果我的理论是正确的,它就在一个线程中。

//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;
}

编辑:

这里有一些关于我在创建 C 和 B 之后如何处理它们以及如何在实际程序中实现它们的更多信息。 所涉及的所有类都是可复制构造的。而 B 中的成员变量 c 在 boost::stable_vector 中。因为对于其他任务,这一切都很好,我假设我的复制构造函数和赋值运算符都可以。 如果我在回调中检查 me 的值,事实证明 me 本身仍然具有所有值,除了指针。

编辑2:

我发现了问题。我复制 B 对象时没有更新父指针。谢谢大家的帮助。

【问题讨论】:

  • 在创建线程时如何将成员函数绑定到它的实际实例?
  • 你的意思是这样吗? std::function&lt;Uint32(Uint32, void*)&gt; t = std::bind(this-&gt;callback, std::placeholders::_1, std::placeholders::_2); l_timer = SDL_AddTimer(l_delay, t, this); ?在这里,我收到“无法从 SDL_Callback 转换为 std::function”错误。
  • SDL_Callback 是否允许用户定义的额外参数void*?否则,将 this 绑定到特定类实例的机会很低,应该从线程内调用其成员函数。
  • SDL_Callback 期望回调函数为 Uint32 callback (Uint32, void*) 您是说额外的 void* 吗?那么不,但我不能使用一对吗?如果是这样,我该怎么办?
  • 好的,处理这个问题的最好方法是拥有一个静态类方法,它需要一个指向class C 的指针。然后在void argument 中传递一个指向C 的有效实例的指针。在回调函数中,将void* 的值转换为C*,调用C::mystatic_callback() 并将C* 作为参数传递。然后你就可以调用C的任何类成员函数了。

标签: c++ multithreading callback


【解决方案1】:

您提供的信息太少,无法确定地回答您。很可能在从另一个线程调用 callback 之前,对象 b 被销毁(可能从创建它的线程中)。

添加一个带有一些日志记录的析构函数到class B。在C::callback() 的开头添加一些日志,这会给你一个提示正在发生的事情。此外,为A 添加一个虚拟析构函数,这对于您有类似A* a = new B(); delete a; 的内容至关重要。

【讨论】:

    【解决方案2】:

    如果您无法通过手动代码审查来检测问题,请使用 valgrind memcheck/helgrind 来帮助您检测任何潜在的内存损坏问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多