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

时间:2011-10-18 15:44:44

标签: c++ pthreads function-pointers

我有基础类和派生类。 他们有一个虚拟功能 - 虚拟空行动() 我怎样才能将它传递给* 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);
  } 
};

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

5 个答案:

答案 0 :(得分:4)

几个月前,我在我的高级设计项目上遇到了这个问题。它需要一些基础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();
};

修改: Woops,如果tidprotectedprivate,则do_action必须为friend。< / p>

答案 1 :(得分:3)

你必须有一个函数,它将一个void指针传递给pthread_create。我自己编写函数,作为一个函数,它指向BaseDerived也可以工作),然后调用参数的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);
  }
};

答案 2 :(得分:2)

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

void *Base::static_action(void *v)
{
    ((Base*)v)->action();
    return NULL;
}

pthread_create(&tid, NULL, &Base::static_action, myObject);

答案 3 :(得分:1)

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

开始方法:

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

静态void *执行方法:

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

答案 4 :(得分:0)

让它保持静态并不能保证工作,但实际上至少在大多数实现方面都有效(并且有足够的人依赖它,我很快就会看到这种变化,我会感到有些惊讶)。