2010-07-01 3 views
6

J'ai une petite enveloppe qui centralisent ce qui est par rapport aux fils:« méthode virtuelle pure appelée » lors de la mise en œuvre d'un boost :: interface wrapper fil

class Thread { 
protected: 
    boost::thread *m_thread; 

    virtual void work() = 0; 

    void do_work() { 
     work(); 
    } 

public: 
    Thread() : m_thread(NULL) {} 
    virtual ~Thread() { 
     catch_up(); 
     delete m_thread; 
    } 

    inline void catch_up() { 
     if(m_thread != NULL) { 
      m_thread->join(); 
     } 
    } 

    void run() { 
     m_thread = new boost::thread(boost::bind(&Thread::do_work, boost::ref(*this))); 
    } 
}; 

Quand je mets en œuvre, dites ce qui suit:

class A : public Thread { 
    void work() {} 
}; 

a:

A a; a.run(); 

Je suis une terminaison d'exécution avec un joli "méthode virtuelle pure appelée" displ ayed. Je pense que c'est l'argument boost :: bind, mais je ne sais pas comment dire "Utiliser une implémentation virtuelle pure" ...

Merci d'avance.

Cordialement,

Mister Mystère

Répondre

6

Votre accident ne se produit que lorsque votre programme se termine immédiatement: il appelle la classe A de destructor qui finitions et appelle la destructor de fil avant le nouveau thread commencé a une chance d'être prévu. Le thread appelle alors votre fonction virtuelle, mais la classe A n'existe plus, il essaie donc d'appeler do_work(), qui appelle le travail virtuel pur(). Voici votre programme avec des sorties supplémentaires:

run() started 
run() ended 
~A() started 
~A() ended 
~Thread() started 
catch_up() started 
do_work() started 
pure virtual method called 

Standard-sage, je pense que ce comportement est indéfini parce que la durée de vie de l'objet a déjà terminé (appel destructor a commencé) quand une référence à elle (boost::ref(*this)) a été utilisé pour appeler do_work () du fil.

Solution: laissez votre fil exécuter avant de détruire votre objet:

A a; a.run(); 
a.catch_up(); 

Ou, comme documentation boost.thread dit, "the user of Boost.Thread must ensure that the referred-to object outlives the newly-created thread of execution."

+0

Eh bien, c'était simple ... Merci, vous l'avez dit clairement. Mais maintenant j'ai un plus gros problème (booléens aléatoires apparemment ...), et je pense que ce sera plus difficile à déboguer. Je n'aurais pas dû utiliser mon "joker" ici pour ça, sinon je paraîtrai indigent ^^ ' –

1

Je vais sortir sur un membre ici, mais je soupçonne que le problème est avec votre fil destructor:

virtual ~Thread() { 
    catch_up(); 
    delete m_thread; 
} 

Si le fil n'a pas Commencé encore, l'appel catch_up() dans le destructeur va démarrer le thread boost en utilisant vtable Thread plutôt que A, comme en C++ au point du destructeur le vtable correspond à la portée du type du destructeur, pas le plus dérivé vtable.

+0

Je pense que nouvelle alloue la poignée de fil après l'avoir créé à droite? Ainsi, vérifier dans catch_up() si m_thread est égal à NULL suffit à le protéger dans le cas où le destructeur est plus rapide que la création du thread. –

+0

Je parle du destructeur de Thread, pas de celui de boost :: thread. – MSN

+0

Je sais, je parlais de ça aussi. Mais maintenant que je comprends, je pense que vous l'avez également souligné, désolé d'avoir mal compris, mon mauvais;) –

Questions connexes