有没有办法将成员函数传递给pthread_cleanup_push?

时间:2014-08-01 20:09:57

标签: c++ pthreads

我想知道将成员函数传递给pthread_clean_push的方法。我不想将清理函数声明为静态并传递对象的引用。以下是场景

class Foo{
public:
   Foo(string name):name(name){};
   void setBar1(){bar1=malloc(4);sleep(20);};
   void setBar2(){bar2=malloc(10);sleep(50);};
   void cleanBar1(void* arg){free(bar1);};
   void cleanBar2(void* arg){free(bar2);};
private:
   string name;
   void* bar1;
   void* bar2;
};

void* myPThread(void* arg){
   Foo theFoo(*(string*)(arg));
   theFoo.setBar1();
   pthread_cleanup_push(&theFoo.cleanBar1,NULL);   //what is the correct way to
   theFoo.setBar2();
   pthread_cleanup_push(&theFoo.cleanBar2,NULL);   //pass clean functions?
   sleep(100);
   pthread_cleanup_pop(1);
   pthread_cleanup_pop(1);
   return NULL;
}

int main(){
   string biryani="biryani";
   string pappu="pappu";
   pthread_t makeBirayani, makePappu;
   pthread_create(&makeBiryani,NULL,&myPThread,(void*)&biryani);
   pthread_create(&makePappu,NULL,&myPThread,(void*)&pappu);
   pthread_join(makeBiryani,NULL);
   pthread_join(makePappu,NULL);
   return 0;
}

我避免了编译时错误 ISO C ++禁止使用(void(*)(void*))&Foo::cleanBar1作为绑定成员函数的地址来形成指向成员函数的指针 pthread_cleanup_push()的参数。但是多线程发生运行时错误(分段错误),因为它在确定清理函数所属的实例时存在不明确性。在这种情况下如何调用here之类的成员函数?语法是什么?

3 个答案:

答案 0 :(得分:3)

Foo::cleanBar1Foo::cleanBar2是非静态成员函数,这意味着它们采用隐式的第一个参数,指向必须调用它们的Foo实例的指针({ {1}}指针)。因此,您无法将指向成员函数的指针传递给this并获得所需的行为。

您需要创建一个调用所需成员函数的调度程序函数,然后将指向该函数的指针传递给pthread_cleanup_push。此调度函数可以是自由函数,也可以是pthread_cleanup_push的{​​{1}}成员函数。例如,

static

然后将其传递给Foo

class Foo{
public:
   Foo(string name):name(name){}
   void setBar1(){bar1=malloc(4);sleep(20);}
   void cleanBar1(){free(bar1);}
   static void bar1_callback(void *arg)
   {
       static_cast<Foo*>(arg)->cleanBar1();
   }

   // ..
private:
   string name;
   void* bar1;
   void* bar2;
};

现在对pthread_cleanup_push的调用将执行pthread_cleanup_push(&Foo::bar1_callback, &theFoo); 并向其传递指向pthread_cleanup_pop实例的指针,然后该实例将调用Foo::bar1_callback成员函数。

答案 1 :(得分:0)

根据我对pthread函数pthread_cleanup_push函数的理解,你可以将一个自由函数的地址(或者可能static的地址传递给类Foo)和一个指向对象的指针然后将呼叫路由到正确的成员。

void clean_bar_1(void* arg)
{
  Foo* p = static_cast<Foo*>(arg);
  p->cleanBar1();
}

然后在myPThread函数:

pthread_cleanup_push(&clean_bar_1, &theFoo);

重复cleanBar2方法。

答案 2 :(得分:0)

成员函数需要知道执行它的对象。这就是标准不允许这种直接参考的原因。

只需使用lambda-wrapper,如:

 pthread_cleanup_push( [](void*a)->void { reinterpret_cast<Foo*>(a)->cleanBar1(NULL);},
                       &theFoo);    //&theFoo will be passed as argument to the function

但是,当调用清理时,你必须确保你的theFoo对象仍然存在,因为你在推送清理函数时给它的地址,这个地址稍后将被用作lambda函数清理的参数。