有没有一种方法可以将成员函数传递给pthread_cleanup_push

Is there a way to pass a member function to pthread_cleanup_push?

本文关键字:函数 pthread push cleanup 成员 一种 方法 有没有      更新时间:2023-10-16

我想知道将成员函数传递给pthread_clean_push的方法。我不想将cleanup函数声明为static并将对象的引用传递给它

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((的参数,使用绑定成员函数的地址来形成指向成员函数的指针。但是多个线程会出现运行时错误(分段错误(,因为它在确定清除函数所属的实例时存在歧义。在这个场景中,如何调用像这里这样的成员函数?语法是什么?

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

您需要创建一个调度程序函数来调用所需的成员函数,然后将指向该函数的指针传递给pthread_cleanup_push。这个分派函数可以是一个自由函数,也可以是Foostatic成员函数。例如,

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,并向其传递一个指向theFoo实例的指针,该实例随后将调用cleanBar1()成员函数。

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

只需使用lambda包装器,如:

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

但是,您必须确保在调用cleanup时您的FOO对象仍然存在,因为您在推送cleanup函数时会给出它的地址,而此地址稍后将被lambda函数用作cleanup的参数。

根据我对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方法。