Ошибка g ++: pthread_create () и указатель на функцию-член

Возможный дубликат:
функция pthread из класса

Я пытаюсь создать поток с помощью процедуры запуска, но g ++ не нравится мой синтаксис.

class myClass
{
  void* myFunction(void* myArg)
  {
    // some code, useless here
  }

  void start()
  {
    pthread_t thread_id;
    int* fd;

    //Some code, useless here.

    pthread_create(&thread_id, 0, &myFunction, (void*) fd);
  }
}

Во время компилятора g ++ сообщает мне, что ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function. Say '&myFunction'.

Он не может преобразовать void (myClass::*) (void*) в void* (*) (void*) для аргумента 3 pthread_create.

Любая идея ?


person Patouf    schedule 19.10.2012    source источник


Ответы (6)


Вам нужно будет объявить myFunction статической, чтобы ее можно было рассматривать как обычную функцию.

person Vaughn Cato    schedule 19.10.2012

Вы не можете использовать обычный функциональный член в качестве подпрограммы потока. Причина в том, что такой член функции требует вызывающего контекста - this указатель на объект, который недоступен для pthread кишок.

Сделайте такую ​​функцию членом static или просто свободной функцией.

person Rost    schedule 19.10.2012

Вы не можете передавать указатель на нестатический метод. Вы можете использовать прокси-функцию, передав указатель на свой экземпляр в качестве параметра в pthread_create и оттуда вызвать myFunction.

person user18428    schedule 19.10.2012

Как сказал компилятор, вы должны использовать статическую функцию с pthread, что-то вроде этого должно работать:

class myClass
{
  static void startThread(void* context)
  {
    ((myClass*)context)->myFunction()
  }

  void myFunction()
  {
    // some code, useless here
  }

  void start()
  {
    pthread_t thread_id;

    //Some code, useless here.

    pthread_create(&thread_id, 0, &startThread, this);
  }
}

Также вы можете использовать структуру в качестве контекста, в котором вы можете передавать этот и другие аргументы, если это необходимо.

person gogoprog    schedule 19.10.2012

Вы можете сделать свою функцию статической или использовать небольшое обходное решение для вызова функции из вашего класса.

void *callMyFunction(void *f)
{
  reinterpret_cast<myClass*>(f)->myFunction();
  return (NULL);
}

class myClass
{
  void* myFunction()
  {
    // some code, useless here
  }

  void start()
  {
    pthread_t thread_id;
    int* fd;

    //Some code, useless here.

    pthread_create(&thread_id, 0, &callMyFunction, (void*) this);
  }
}

Если вы хотите передать параметры в myClass::myFunction, вам нужно будет создать небольшую структуру, подобную этой

struct s_param
{
  void  *ptr;
  int   param1;
  char  param2;
  /* other variables */
};

callMyFunction станет

void *callMyFunction(void *bundle)
    {
      reinterpret_cast<myClass*>(bundle->ptr)->myFunction(bundle->param1, bundle->param2/*, ...*/);
      return (NULL);
    }
person Zoneur    schedule 19.10.2012

Как указано вашим компилятором pthread_create ожидайте void* (*)(void*), но вы предоставляете функцию с очень похожим, но другим синтаксисом:

Каждая функция класса, отличного от static, имеет скрытый параметр с именем this типа class*, поэтому теперь ваша функция void* (*)( class*, void* ), что не соответствует ожидаемому pthread_create. Вы должны предоставить функцию с такой же архитектурой.

Также, если в вашем классе есть такая функция, как void* someFunction(), она может совпадать с функцией, которую ожидает pthread_create, конечно, это не разрешено компилятором, и для этого также есть причина. Причина в соглашении о вызовах, то есть о том, как параметры, передаваемые в функцию, компилятор C ++ разрешил передавать this в регистры! поэтому он не будет соответствовать функции, ожидаемой pthread_create. Это может быть решено некоторыми компиляторами, которые позволяют вам выбрать соглашение о вызовах вашей функции, но это нестандартно, поэтому лучше всего написать прокси-функцию как:

static void* my_thread_routine_proxy(void* param) {
    static_cast<my_class*>(param)->my_thread_routine();
}

Но если вам нужно передать больше параметров, вы должны создать для него структуру и передать свои параметры в этой структуре, но не помните, что переданная структура должна оставаться действительной до тех пор, пока ваша функция не будет фактически вызвана как новый поток. Значит, это должен быть глобальный или динамически выделяемый объект.

person BigBoss    schedule 19.10.2012