указатель функции параметра pthread_create

#c #function #pointers #pthreads

#c #функция #указатели #pthreads

Вопрос:

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

Пожалуйста, дайте мне знать, что я делаю неправильно, и как я могу это исправить в следующем коде:

 #include "RobotNodes.cpp"

int main(int argc, char** argv){

int i, numRobotsToInit = 7;

//declare run function pointer
void (*run)();

//create array of robot nodes 
RobotNodes* robots[numRobotsToInit]; 

//init robot nodes
for(i = 0; i<numRobotsToInit; i  ){
    robots[i] = new RobotNodes(i, 0.2, 0.2);
}


for(i = 0; i<numRobotsToInit; i  ){
        run = amp;robots[i]->run;
        pthread_t thread; 
    pthread_create(amp;thread, NULL, (void*(*)(void*))run, NULL);       
}
}
  

Ошибка, которую я получаю, заключается в следующем:
error: lvalue required as unary ‘amp;’ operand

Редактировать: run() — это метод из класса RobotNodes.cpp это входит в верхнюю часть этого класса.

Комментарии:

1. Вы уверены, что не путаете свободные функции с функциями-членами?

Ответ №1:

Похоже, в классе есть нестатическая функция-член RobotNodes , и вы, похоже, думаете, что тип функции-члена таков void (*)() . Если это так, то вы ошибаетесь.

Тип нестатической функции-члена и свободной функции не совпадают, даже если они имеют точно такую же подпись!

Поэтому я бы посоветовал вам определить статическую функцию, вызываемую start как:

 class RobotNodes
{
   public:
        void run(); //define it as you like

        static void* start(void *pdata)
        {
             RobotNodes *robot = static_cast<RobotNodes*>(pdata);
             robot->run(); //forward it
             return 0; //or return as the documentation says
        }
};
  

Затем используйте start как :

 std::vector<pthread_t> threads(numRobotsToInit);
for(i = 0; i<numRobotsToInit; i  )
{
    pthread_create(amp;threads[i], NULL, RobotNodes::start, amp;robots[i]);       
}
  

Кроме того, обратите внимание, что я создал вектор pthread_t вне цикла; это потому, что каждый экземпляр потока должен отличаться, если они являются разными потоками, и, кроме того, каждый экземпляр потока должен продолжать существовать даже после остановки цикла.

Ответ №2:

проблема в том, что вы пытаетесь указать указатель на функцию-член, а не на стандартную функцию.

Вместо этого передайте робота в качестве параметра функции, которая сообщает роботу о запуске:

 extern "C" void* run_robot(void* robot) __attribute__((noreturn));
void* run_robot(void* robot) {
    RobotNodes* node(static_cast<RobotNodes*>(robot));
    node->run();
    pthread_exit(0);
}
...
pthread_create(amp;thread, NULL, run_robot, amp;robots[i]);
  

Ответ №3:

Где определяется run?

Использование pthread_create(amp;thread, ...) является плохим, поскольку thread переменная локальна для цикла for и выйдет из области видимости в конце for .

попробуйте вместо этого:

 for(i = 0; i<numRobotsToInit; i  ){
  run = amp;robots[i]->run;
  pthread_t* thread = new pthread_t;  //you will get a memory leak unless you store these to delete later
  pthread_create(thread, NULL, run, NULL);       
}
  

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

Создайте вызываемую статическую функцию dispatch или что-то в этом роде, передайте ей указатель на экземпляр класса, для которого вы хотите вызвать функцию.

Комментарии:

1. Извините, забыл включить, что run() из другого класса (RobotNodes), который включен в этот класс. При запуске кода с вашими изменениями получаю следующие ошибки: ошибка: не удается преобразовать ‘void (RobotNodes::*) ()’ в ‘void ( )()’ при присваивании ошибка: недопустимое преобразование из ‘void ( ) ()’ в ‘void * ( ) (void )’ошибка: инициализация аргумента 3 ‘int pthread_create(pthread_t*, const pthread_attr_t*, void* ( )(void ), void*)’