mardi 18 juillet 2017

Inheritance, background thread and RAII

I have a base class that can start background thread, and stop it when needed. That thread calls two virtual methods Open() and Close(). So all inherited classes can re-implement this methods, but not starting/stoping thread routine (it more difficult than in example). I want to follow RAII principle and start/stop thid thread in constructor/destructor of base class.

The problem is, that calling virtual methods in constructor/destructor is a bad practice and didn't work in my case. Here is a shot example of my problem:

#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;
}

The output is:

Inherited open
Base close

And without sleep is:

Base open
Base close

My current approach is to call Start() method after constructor and Stop() before destructor, but I want solution with 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();
  }
}

Aucun commentaire:

Enregistrer un commentaire