2009-11-29 2 views
1

Utilisation de C++.Je suis nouveau sur les threads, que signifie cette erreur de compilation?

pthread_t threads[STORAGE]; // 0-99 

... 

void run() 

Error>>> int status = pthread_create(&threads[0], NULL, updateMessages, (void *) NULL); 
if (status != 0) 
{ 
    printf("pthread_create returned error code %d\n", status); 
    exit(-1); 
} 

...

void ClientHandler::updateMessages(void *) 
{ 
    string reqUpdate = "91"; // Request for update 
    string recvMSG; 
    while (true) 
    { 
     sleep(5); 
     sending(sock,reqUpdate); // send 
     recvMSG = receiving(sock); // receive 
     QString output(recvMSG); 
     emit signal_chat(output, 0); // Print message to text box 
    } 
} 

...

Compile Erreur: TCPClient.cpp:109: error: argument of type ‘void (ClientHandler::)(void*)’ does not match ‘void* (*)(void*)’

Je ne peux pas comprendre ce qui est erroné. Merci d'avance.

Répondre

7

Un pointeur sur une fonction membre est différent d'une fonction globale avec la même signature car la fonction membre a besoin d'un objet supplémentaire sur lequel elle opère. Par conséquent, les pointeurs vers ces deux types de fonctions ne sont pas compatibles.

Dans ce cas, cela signifie que vous ne pouvez pas passer un pointeur de fonction membre à pthread_create, mais uniquement un pointeur vers une fonction non-membre (ou statique). Un travail autour de ce problème est d'utiliser le paramètre vient de pthread_create pour passer un pointeur vers un objet à une fonction globale qui appelle ensuite la méthode de l'objet passé:

class ClientHandler { 
public: 
    void updateMessages(); 
    void run(); 
}; 

// Global function that will be the threads main function. 
// It expects a pointer to a ClientHandler object. 
extern "C" 
void *CH_updateMessages(void *ch) { 
    // Call "real" main function 
    reinterpret_cast<ClientHandler*>(ch)->updateMessages(); 
    return 0; 
} 

void ClientHandler::run() { 
    // Start thread and pass pointer to the current object 
    int status = pthread_create(&threads[0], NULL, CH_updateMessages, (void*)this); 
    ... 
} 
+0

Merci beaucoup ^^ –

6

Cela n'a rien à voir avec les threads, c'est une erreur C++ normale, vous passez simplement un type de pointeur de fonction incompatible.

Un pointeur de fonction n'est pas identique à un pointeur de fonction d'instance membre, même si sa signature est la même; c'est parce qu'il y a une référence implicite à * ceci passé. Vous ne pouvez pas éviter cela.

+0

donc je ne peux pas créer de threads à partir d'un objet? –

+0

Vous pouvez modifier updateMessages pour qu'il devienne une fonction statique de votre classe. Ensuite, si vous voulez accéder aux données de membre, vous pouvez passer le pointeur "this" à pthread_create comme variable de contexte, et vous le recevrez dans le premier paramètre de votre fonction updateMessages. – rossoft

+0

@rossoft oui cela fonctionnerait. – MarkR

0

Comme pthread_create prend une fonction libre, créer une fonction statique (est une fonction libre) à l'intérieur ClientHandler

static void Callback(void * this_pointer,int other_arg) { 
    ClientHandler* self = static_cast< ClientHandler*>(this_pointer); 
    self-> updateMessages(other_arg); 
} 
and call pthread_create as follows 

pthread_create(&threads[0], NULL, &ClientHandler::Callback, (void *) pointer_to_ClientHandler,int other_arg); 

Cela fonctionne parce que Callback est fonction libre

+1

Ceci est techniquement interdit car l'ABI pour les fonctions membres statiques est défini par le compilateur (et donc vous ne pouvez pas garantir) la convention d'appel. __Si cela fonctionne sur votre compilateur de plate-forme, vous êtes juste chanceux. Dans pthreads (parce qu'il s'agit d'une bibliothèque C), il s'attend à ce que le pointeur de fonction utilise l'ABI "C". Ainsi, la fonction doit être marquée comme extern "C" (à partir du code C++) pour garantir que la convention d'appel correcte est utilisée. –

+0

merci, mais je ne suis pas en mesure de supprimer le poste – yesraaj

-1

vous passez une fonction membre au lieu d'un global, normal,.

définir Just:

void updateMessages(void *) { 
static ClientHandler c; 
// use c.. 
} 
0

YoLinux a un beau tutoriel pthread que mon vous aide à apprendre sur les threads.

0

Comme d'autres l'ont déjà dit, le problème est que les signatures entre les fonctions sont différentes. Les fonctions membres de classe ont toujours un paramètre supplémentaire "secret", le pointeur this. Vous ne pouvez donc jamais passer une fonction membre où une fonction globale est attendue. Vous pouvez contourner ce problème avec des bibliothèques telles que Boost.Bind ou en faisant de la fonction un membre statique de la classe.

Mais la solution la plus simple et la plus élégante consiste à utiliser une API de threading différente. Boost.Thread est une très belle bibliothèque de threading pour C++ (pthreads est conçu pour C, et c'est pourquoi il ne joue pas bien avec les fonctionnalités C++ telles que les méthodes de classe).

Je recommande d'utiliser cela.

Votre code pourrait être réécrite comme quelque chose comme ceci:

class ClientHandler { 
public: 
    ClientHandler(/* All the parameters you want to pass to the thread. Unlike pthreads you have complete type safety and can pass as many parameters to this constructor as you like */){...} 
    void operator()() // boost.thread calls operator() to run the thread, with no parameters. (Since all parameters were passed in the constructor and saved as member variables 
    { 
    string reqUpdate = "91"; // Request for update 
    string recvMSG; 
    while (true) 
    { 
     sleep(5); 
     sending(sock,reqUpdate); // send 
     recvMSG = receiving(sock); // receive 
     QString output(recvMSG); 
     emit signal_chat(output, 0); // Print message to text box 
    } 
    } 
    // whatever arguments you want to pass to the thread can be stored here as member variables 
}; 


boost::threead_group gr; // can store all your threads here, rather than being limited to your fixed-size array 

gr.create_thread(ClientHandler(/* construct a ClientHandler object with the parameters you like*/)); 
Questions connexes