c++:如何定义类方法作为线程的启动例程(使用pthread库)

C++: how to define a class method as a start routine to thread (with pthread library)

本文关键字:线程 启动 例程 使用 pthread 类方法 何定义 c++ 定义      更新时间:2023-10-16

我有一个基类派生类。它们有一个虚函数——虚void action()我怎么能把它传递给*pthread_create()*函数?

示例(错误):

class Base{
  protected:
     pthread_t tid;
  public:
  virtual void* action() = 0;
};
class Derived : public Base{
  void* action();
  Derived(){
    pthread_create(&tid, NULL, &action, NULL);
  } 
};

也许应该是静态的?我尝试了很多组合,但无法找到解决方案。

几个月前我在做我的高级设计项目时遇到了这个问题。它需要对c++的基本机制有一定的了解。

根本问题是指向函数的指针不同于指向成员函数的指针。这是因为成员函数有一个隐式的第一个参数this

man页:

int pthread_create(pthread_t *thread,
                   const pthread_attr_t *attr,
                   void *(*start_routine) (void *),
                   void *arg);

线程入口点为void* (*)(void*)。函数Base::action的类型是void* (Base::*)()。这个丑陋的类型声明的Base::部分表示this的类型。类型差异是编译器不接受你的代码的原因。

有两件事我们需要修复使这个工作。不能使用成员函数,因为指向成员函数的指针不会将this绑定到实例。我们还需要一个void*类型的参数。值得庆幸的是,这两个修复是齐头并进的,因为解决方案是显式地传递this

class Base {
public:
    virtual void* action() = 0;
protected:
    pthread_t tid;
    friend void* do_action(void* arg) {
        return static_cast<Base*>(arg)->action();
    }
};
class Derived : public Base {
public:
    Derived() {
        // This should be moved out of the constructor because this
        // may (will?) be accessed before the constructor has finished.
        // Because action is virtual, you can move this to a new member
        // function of Base. This also means tid can be private.
        pthread_create(&tid, NULL, &do_action, this);
    }
    virtual void* action();
};

Edit:哎呀,如果tidprotectedprivate,那么do_action需要是friend

你必须有一个函数,它接受一个void指针传递给pthread_create。我自己写这个函数,作为一个函数,它接受一个指向Base的指针(Derived也可以工作),然后调用参数的action函数。然后,您可以创建一个线程来运行该函数并接收this作为参数:

void *f(void *param)
{
    Base* b = (Base *)param;
    return b->action();
}
class Derived : public Base{
  void* action();
  Derived() {
    pthread_create(&tid, NULL, f, this);
  }
};

确实必须是静态的。您还需要将您的对象作为参数传递给pthread_create:

void *Base::static_action(void *v)
{
    ((Base*)v)->action();
    return NULL;
}
pthread_create(&tid, NULL, &Base::static_action, myObject);

我通常做类似的事情,我将让您填写其他细节(错误处理,锁定等):

Start方法:

bool pthreadBase::start()
{
   return pthread_create(&threadID, NULL, &execute,this);
}

静态void* Execute方法:

void *pthreadBase::execute(void *t)
{
   reinterpret_cast<pthreadBase *> (t)->processLoop();
   return NULL;
}
之后,你可以创建一个名为processLoop的虚拟方法,它将作为线程的入口点。

下面是一个简单的实现(未测试):

class theThread: public pthreadBase
{
   public:
      theThread(SharedMemoryStructure *SharedMemory)
      {
         _Running = start();
         _Shared = SharedMemory;
      }
      ~theThread()
      {
         stop(); //Just do a join or something
         _Running = false;
      }
   private:
      void processLoop()
      {
         while(_Shared->someQuitFlag() == false)
         {
            /*Do Work*/
         }
      }
   private:
      bool _Running;
      SharedmemoryStructure *_Shared;
};

将其设置为静态并不能保证一定有效,但实际上至少在大多数实现中是有效的(并且有足够多的人依赖于它,因此我也会对很快看到这种变化感到有点惊讶)。