Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 thread doesn't work with virtual member function

I'm trying to get a class run a thread, which will call a virtual member function named Tick() in a loop. Then I tried to derive a class and override the base::Tick().

but when execute, the program just call the base class's Tick instead of override one. any solutions?

#include <iostream>
#include <atomic>
#include <thread>
#include <chrono>

using namespace std;

class Runnable {
 public:
  Runnable() : running_(ATOMIC_VAR_INIT(false)) {

   }
  ~Runnable() { 
    if (running_)
      thread_.join();
  }
  void Stop() { 
    if (std::atomic_exchange(&running_, false))
      thread_.join();
  }
  void Start() {
    if (!std::atomic_exchange(&running_, true)) {
      thread_ = std::thread(&Runnable::Thread, this);
    }
  }
  virtual void Tick() {
    cout << "parent" << endl;
  };
  std::atomic<bool> running_;

 private:
  std::thread thread_;
  static void Thread(Runnable *self) {
    while(self->running_) {
      self->Tick();
      std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
  }
};

class Fn : public Runnable {
 public:
  void Tick() {
    cout << "children" << endl;
  }
};

int main (int argc, char const* argv[])
{
  Fn fn;
  fn.Start();
  return 0;
}

outputs:

parent
like image 956
xiaoyi Avatar asked May 17 '12 11:05

xiaoyi


1 Answers

You can't let an object run out of scope until you're finished using it! The return 0; at the end of main causes fn to go out of scope. So by the time you get around to calling tick, there's no guarantee the object even exists any more.

(The logic in ~Runnable is totally broken. Inside the destructor is way too late -- the object is already at least partially destroyed.)

like image 72
David Schwartz Avatar answered Oct 29 '22 23:10

David Schwartz