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

发布于 2024-12-11 01:10:07 字数 428 浏览 1 评论 0原文

我有一个类和派生类。 他们有一个虚拟函数 - virtual 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);
  } 
};

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

i have a Base class and Derived class.
they have a virtual function- virtual void action()
how can i pass it to *pthread_create()* function?

example(with errors):

class Base{
  protected:
     pthread_t tid;
  public:
  virtual void* action() = 0;
};

class Derived : public Base{
  void* action();
  Derived(){
    pthread_create(&tid, NULL, &action, NULL);
  } 
};

maybe it should be static?
i tried lot of combinations but cant find solution..

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

一梦等七年七年为一梦 2024-12-18 01:10:07

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

编辑:糟糕,如果 tidprotectedprivate,那么 do_action 需要成为朋友

I ran into this problem a couple months back working on my senior design project. It requires some knowledge of underlying C++ mechanics.

The underlying issue is that pointers to functions are different from pointers to member functions. This is because member functions have an implicit first parameter, this.

From the man page:

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

The thread entrance point is a void* (*)(void*). Your function, Base::action has the type void* (Base::*)(). The Base:: part of that ugly type declaration denotes the type of this. The type discrepancy is why the compiler won't accept your code.

There's two things we need to fix to make this work. We can't use a member function, because pointers to member functions don't bind this to an instance. We also need a single parameter of type void*. Thankfully, these two fixes go hand in hand because the solution is to explicitly pass this ourselves.

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: Woops, if tid is protected or private, then do_action needs to be a friend.

你是暖光i 2024-12-18 01:10:07

您必须有一个函数将一个 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);
  }
};

You have to have a function that takes one void pointer to pass to pthread_create. I'd write the function myself, as a function that takes a pointer to Base (Derived would work as well), then call the action function of the parameter. You can then create a thread that runs the function and received this as parameter:

void *f(void *param)
{
    Base* b = (Base *)param;
    return b->action();
}

class Derived : public Base{
  void* action();
  Derived() {
    pthread_create(&tid, NULL, f, this);
  }
};
jJeQQOZ5 2024-12-18 01:10:07

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

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

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

Indeed it has to be static. You'll also need to pass your object as an argument to pthread_create:

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

pthread_create(&tid, NULL, &Base::static_action, myObject);
来日方长 2024-12-18 01:10:07

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

启动方法:

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

I usually do something similar to this, I'll let you fill in the other details (error handling, locking, etc):

Start method:

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

Static void* Execute method:

void *pthreadBase::execute(void *t)
{
   reinterpret_cast<pthreadBase *> (t)->processLoop();
   return NULL;
}

After, you can just make a virtual method called processLoop that will act as an entry point for your thread.

Here's a simple implementation (NOT TESTED):

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;
};
相思碎 2024-12-18 01:10:07

使其静态并不能真正保证工作,但实际上至少对于大多数实现来说确实有效(并且有足够多的人依赖它,我会有点惊讶地看到这种变化很快)。

Making it static isn't really guaranteed to work, but actually does at least with most implementations (and enough people depend on it that I'd be a little surprised to see that change soon either).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文