J'ai une classe de base qui peut démarrer le fil d'arrière-plan et l'arrêter si nécessaire. Ce thread appelle deux méthodes virtuelles Open()
et Close()
. Ainsi, toutes les classes héritées peuvent ré-implémenter ces méthodes, mais pas démarrer/arrêter la routine des threads (c'est plus difficile que par exemple). Je veux suivre le principe RAII et démarrer/arrêter ce thread dans le constructeur/destructeur de la classe de base.Héritage, fil d'arrière-plan et RAII
Le problème est que l'appel de méthodes virtuelles dans le constructeur/destructeur est une mauvaise pratique et n'a pas fonctionné dans mon cas. Voici un exemple tiré de mon problème:
#include <iostream>
#include <thread>
#include <atomic>
class Base {
public:
Base() {
bg_thread_ = std::thread([this] {
Open();
while(!is_stop_) {
// do stuff
}
Close();
});
}
~Base() {
is_stop_ = true;
if(bg_thread_.joinable()) {
bg_thread_.join();
}
}
private:
virtual void Open() {
std::cout << "Base open" << std::endl;
}
virtual void Close() {
std::cout << "Base close" << std::endl;
}
std::thread bg_thread_;
std::atomic<bool> is_stop_{false};
};
class Inherited : public Base {
virtual void Open() override {
std::cout << "Inherited open" << std::endl;
}
virtual void Close() override {
std::cout << "Inherited close" << std::endl;
}
};
int main() {
Inherited inherited;
std::this_thread::sleep_for(std::chrono::seconds(1));
return 0;
}
La sortie est:
Inherited open
Base close
Et sans sommeil est:
Base open
Base close
Mon approche actuelle consiste à appeler la méthode Start()
après constructeur et Stop()
avant destructeur, mais je veux une solution avec RAII.
void Start() {
bg_thread_ = std::thread([this] {
Open();
while(!is_stop_) {
// do stuff
}
Close();
});
}
void Stop() {
is_stop_ = true;
if(bg_thread_.joinable()) {
bg_thread_.join();
}
}
Vous pouvez appeler 'Stop()' dans le destructeur et vous devriez être en sécurité. – rozina
Si j'appelle 'Start()' dans le constructeur et 'Stop()' dans destructor, la sortie sera: Inherited open Base close –
Actuellement, la classe de base 'Close' et' Open' sont purement virtuelles. Et si j'appelle 'Stop()' dans la classe Base destructor, le programme va planter avec l'erreur 'Pure virtual called called' –