#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*)’