C ++: как определить метод класса как начальную подпрограмму для потока (с библиотекой pthread) - PullRequest
4 голосов
/ 18 октября 2011

у меня есть базовый класс и производный класс.у них есть виртуальная функция - virtual void action () как я могу передать ее в функцию * pthread_create () *?* может быть, это должно быть статичным?Я попробовал много комбинаций, но не могу найти решение ..

Ответы [ 5 ]

4 голосов
/ 19 октября 2011

Я столкнулся с этой проблемой пару месяцев назад, работая над своим старшим дизайнерским проектом.Это требует определенных знаний о базовой механике 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: Woops, если tid равно protected или private, тогда do_action должно быть friend.

3 голосов
/ 18 октября 2011

У вас должна быть функция, которая принимает один пустой указатель для передачи на 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);
  }
};
2 голосов
/ 18 октября 2011

Действительно, оно должно быть статичным.Вам также нужно будет передать свой объект в качестве аргумента pthread_create:

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

pthread_create(&tid, NULL, &Base::static_action, myObject);
1 голос
/ 18 октября 2011

Я обычно делаю что-то похожее на это, я позволю вам заполнить другие детали (обработка ошибок, блокировка и т. Д.):

Метод запуска:

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

Статическая пустота * Выполнить метод:

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;
};
0 голосов
/ 18 октября 2011

Создание статического кода на самом деле не гарантирует работоспособность, но на самом деле работает, по крайней мере, с большинством реализаций (и от этого зависит достаточное количество людей, что я был бы немного удивлен, увидев это изменение в ближайшее время).

...