I am trying to build a service
object which can run (i.e. execute it's run()
function) in a separate thread. This is the service object
#include <boost/noncopyable.hpp>
#include <atomic>
#include <thread>
#include <iostream>
class service : public boost::noncopyable {
public:
service() : stop_(false), started_(false) { }
virtual ~service() {
stop();
if (thread_.joinable()) {
thread_.join();
}
}
virtual void stop() { stop_ = true; }
virtual void start() {
if (started_.load() == false) {
started_ = true;
thread_ = std::thread([&] () {
run();
});
}
}
protected:
virtual void run() = 0;
std::atomic<bool> stop_;
std::atomic<bool> started_;
std::thread thread_;
};
I am the creating a test
class which inherits from this abstract class and is called in the main()
function
class test : public service {
public:
test() : service() {
std::cout<< "CTOR" << std::endl;
start();
}
~test() {
std::cout<< "DTOR" << std::endl;
}
protected:
void run() override {
std::cout << "HELLO WORLD" <<std::endl;
}
};
int main() {
test test1;
return 0;
}
Now when I execute this, why do I get an error saying pure virtual function called
? The run()
function is clearly overridden in the test
class. Whats worse is that it runs correctly sometimes?
$ ./a.out
CTOR
DTOR
pure virtual method called
terminate called without an active exception
$ ./a.out
CTOR
DTOR
pure virtual method called
terminate called without an active exception
$ ./a.out
CTOR
DTOR
pure virtual method called
terminate called without an active exception
$ ./a.out
CTOR
DTOR
HELLO WORLD
$ ./a.out
CTOR
DTOR
pure virtual method called
terminate called without an active exception
What could be going wrong here?
A virtual method can be created in the base class by using the “virtual” keyword and the same method can be overridden in the derived class by using the “override” keyword.
It is not mandatory for the derived class to override (or re-define the virtual function), in that case, the base class version of the function is used.
If you don't use virtual functions, you don't understand OOP yet. Because the virtual function is intimately bound with the concept of type, and type is at the core of object-oriented programming, there is no analog to the virtual function in a traditional procedural language.
A private virtual function can be overridden by derived classes, but can only be called from within the base class.
Follow along, step by step:
1) You construct the object.
2) You execute the following piece of code:
if (started_.load() == false) {
started_ = true;
thread_ = std::thread([&] () {
run();
});
}
The parent thread immediately returns to main()
where it immediately exits and destroys your object.
Here's your bug:
start()
is going to reach the call to run()
, above, before the parent thread terminates the process. Both the child thread, and the parent thread runs concurrently.So, every once in a while, the parent thread will destroy the object before the child thread gets in gear, and calls run
().
At this point, the object whose run
() method gets invoked, is already destroyed.
Undefined behavior.
The assertion you're hitting, every once in a while, is one possible result of this undefined behavior.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With