2010-10-01 8 views
1

Je commence juste à apprendre le C++ et j'essaye de rendre la classe Thread qui a les fonctionnalités de base de la classe Java Thread. Ce que j'essaie de faire est de créer une classe que vous sous-classez, d'écrire une méthode Run (qui est pure virtuelle dans la classe de base), créez un objet de la sous-classe appelez la méthode start et vous avez thread. Le problème est que dans la façon dont j'utilise C++, la répartition n'est pas faite correctement - c'est comme si la fonction Run n'est pas virtuelle, la méthode Run de la classe de base est appelée.Méthode virtuelle & this pointeur

Voici le code pour l'en-tête

#ifndef _THREAD_H_ 
#define _THREAD_H_ 

#include <pthread.h> 

class Thread { 
public: 
    Thread(); 

    void Start(); 

    ~Thread(); 

protected: 
    virtual void Run() = 0; 

private: 
    static void *RunWrapper(void *); 

    pthread_t thread; 
}; 

#endif 

La mise en œuvre

#include "thread.h" 

#include <pthread.h> 

Thread::Thread() { 
} 

void Thread::Start() { 
    pthread_create(&thread, NULL, Thread::RunWrapper, (void *) this); 
} 

void *Thread::RunWrapper(void *arg) { 
    Thread *t = (Thread *) arg; 
    t->Run(); 
    return arg; 
} 

Thread::~Thread() { 
    pthread_join(thread, NULL); 
} 

Et le fichier qui essaie réellement de faire quelque chose

#include <iostream> 

#include "thread.h" 

class MyThread : public Thread { 
protected: 
    void Run() { 
    std::cout << "The thread is runned" << std::endl; 
    } 
}; 

int main(void) { 
    MyThread thread; 
    thread.Start(); 
    return 0; 
} 

L'erreur que je continue à obtenir la 10 dernières heures est:

pure virtual method called 
terminate called without an active exception 
+0

Si vous voulez vraiment copier la fonctionnalité Java, copiez le package java.util.concurrent à la place. Il a des concepts beaucoup plus avancés pour le multithread comme les exécuteurs, les contrats à terme, les verrous et les mutex. Mais si vous allez aussi loin, il suffit d'utiliser boost: il a déjà tout ce truc en place. –

Répondre

5

Le problème est que votre objet MyThread dans le principal est détruit dès que le La fonction principale retourne, ce qui arrive probablement avant que le nouveau thread ne contacte réellement sa méthode Start. Dans le cadre du processus de destruction, vtable sera réinitialisé sur le vtable de la classe de base avant d'appeler le destructeur de classe de base. Ainsi, lorsque l'appel RunWrapper est exécuté, il finit par déclencher l'erreur de méthode virtuelle pure. Appeler une méthode sur un objet détruit entraîne un comportement indéfini, donc tout peut arriver; Ce comportement est un accident de la façon dont votre compilateur C++ implémente des destructeurs et l'allocation de pile.

+0

Oui, c'était le problème. Merci beaucoup! Lors de l'apprentissage d'une nouvelle langue, on pense que tous les problèmes sont générés par la langue :). –

0

Vous ne savez pas exactement ce qui cause l'erreur, mais ce que vous faites est mauvais: votre objet MyThread peut sortir de la portée avant que votre thread n'y accède. Il est tout à fait possible que la portée ait disparu et que le pointeur ne soit plus valide au moment où votre thread commence à traiter. Essayez d'allouer votre objet sur le tas, et voyez si cela fonctionne (alors, en supposant que cela fonctionne, déterminez comment libérer l'objet lorsque le thread est terminé).

Oh, et vous aurez envie de la prochaine sortie de votre application (par retour de principal) jusqu'à ce que votre fils se fait aussi ...

+0

Je l'ai réparé en utilisant un mécanisme de synchronisation. Merci! –

+0

Eh bien, il ne sera pas totalement parti, à cause de l'appel de 'pthread_join' dans' Thread :: ~ Thread() '. Mais quand Thread :: ~ Thread s'exécute, l'objet a déjà perdu son identité en tant que classe dérivée (le destructeur dérivé a déjà été exécuté) - pendant la destruction, les méthodes virtuelles sont appelées non-virtuelles. –

-2

Le problème est que vous appelez Start, qui appartient à la classe Thread. Cette méthode appelle ensuite Run, qui appellera la méthode Run de la classe Thread. Malheureusement, vous ne pouvez pas appeler la méthode substituée à partir de la classe de base.

+1

Ce n'est pas correct. C'est exactement ce que font les méthodes virtuelles. – Nick

+0

Vous ne pouvez pas les appeler depuis les méthodes de la classe de base. –

+0

Je peux appeler Run sur la sous-classe car j'utilise un pointeur et la méthode est virtuelle. –

Questions connexes