I encountered a crash from calling a pure virtual method, due to a race condition where other threads are still calling methods of a derived class when it's already destroyed. Here's the gist of it:
class Resource
{
protected:
Resource();
virtual ~Resource();
public:
virtual void *lock_shared() = 0;
virtual void unlock_shared() = 0;
// Wait for all other threads to finish.
void sync()
{
mutex.lock();
mutex.unlock();
}
protected:
std::shared_mutex mutex;
};
Resource::~Resource()
{
sync();
}
class Image : public Resource
{
public:
Image();
~Image() override;
void *lock_shared() override
{
mutex.lock_shared();
return accessData();
}
void unlock_shared() override
{
processData();
mutex.unlock_shared();
}
};
Note that when an object of type Image gets destroyed, the intention is to wait for all threads with shared access to finish. However, due to the C++ destructor calling order, Image::~Image() is done by the time we sync() in Resource::~Resource, meaning the object is no longer of type Image, and we can't call any of Image's methods. Other threads still holding a lock will however try to call Image::unlock() when they're done, resulting in a pure virtual call to Resource::unlock() and aborting the program.
The apparent solution is simple: call sync() in Image::~Image() instead.
Unfortunately this is very prone to happening again whenever I derive a new class from Resource, or, from Image. I've added an assert() to Resource::~Resource() to check that try_lock() is always successful, but that doesn't help when I derive from Image.
So I was wondering if anyone knows a more foolproof way to prevent this race condition once and for all. Thanks.
As an idea, if you are ok with using some factory for creating objects of classes derived from Resource rather than explicitly create them, you can make this factory return std::unique_ptr<DerivedResource> with custom deleter which would call p_obj->sync() before actually deleting an owned instance of p_obj.
Related
I just had to put in a fix for a difficult-to-find error, but I am not happy about the fix. Our application is C++ running in Windows, and the error was a pure virtual call crash. Here is some background:
class Observable
{
public:
Observable();
virtual ~Observable();
void Attach(Observer&); // Seize lock, then add Observer to the list
void Detach(Observer&); // Seize lock, then remove Observer from the list
void Notify(); // Seize lock, then iterate list and call Update() on each Observer
protected:
// List of attached observers
};
class Subject : public Observable
{
// Just important to know there is a subclass of Observable
}
class Observer
{
public:
Observer();
virtual ~Observer(); // Detaches itself from the Observable
void Update() = 0;
};
class Thing : public Observer
{
public:
void Update(); // What it does is immaterial to this question
};
Because this is a multi-threaded environment, there are locks in place for Attach(), Detach(), and Notify(). Notify() seizes the lock and then iterates the list of observers and calls Update() on each one.
(I hope this is enough of a background without having to post the complete body of code.)
The problem arose when an observer was being destroyed. On destruction, the Observer detaches itself from the Observable. At the same time, in another thread, Notify() is being called on the Subject. My original thought was that we were protected because of the locks in Detach() (called on destruction of the Observer), and Notify(). However, C++ destroys the subclass first, then the base class. This meant that, before the lock in Detach() was obtained which would have prevented the Notify() function from continuing, the implementation of the pure virtual Update() function was destroyed. The Notify() function continued (because it had already obtained the lock) and attempted to call Update(). The result is a crash.
Now, here is my solution, which works, but gives me a queasy feeling. I changed the Update() function from being pure virtual to just being virtual and provided a body that did nothing. The reason this bothers me is that Update() is still being called, but on a partially destructed object. In other words, I am getting away with something, but I am not wild about the implementation.
Other options discussed:
1) Move the locking into the subclasses. Not desirable because it forces the developer of each subclass to duplicate the logic. And if he omits the locking, bad things can happen.
2) Force the destruction of the observer to occur via a Destroy() function. Honestly, I wasn't sure how to implement this for stack-based objects.
3) Have the subclass call a "PreDestroy()" function in its destructor to notify the base class that destruction is imminent. I wouldn't know how to force this, and forgetting it could lead to hard-to-find runtime errors.
Can anyone offer any suggestions as to a better way to protect against these types of crashes? I have this unpleasant feeling that I am missing the elephant in the room.
JAB
This problem is an illustration of a more general consequence of multi-threaded design: no object that is affected by multiple threads can provide a guarantee of no concurrent access to itself at any point in time. This consequence is the elephant in the room that is giving you the unpleasant feeling you describe at the end of your question.
In short, your problem is that Attach(), Detach(), and Notify() are responsible for both grabbing the appropriate lock and doing their thing. They need to be able to assume the lock is grabbed before they are called.
Unfortunately, the solution requires a more complicated design. It is necessary for some single source that is independent of your objects (or classes) to mediate the construction, updating (including attaching and detaching), and destruction of all your objects. And it is necessary to prevent any of those processes from occurring independently of the mediator.
It is a design choice whether you prevent those processes by technical means (e.g. access control, etc) or simply state policies that all your types must comply with. That choice depends on whether you can rely on your developers (including yourself) to follow policy guidelines.
About your solutions:
Not good, because of the reasons you give.
Ok. Additionally, define ~Observer() as protected (as any other destructor of derived classes) to avoid calling delete directly and write a member void Destroy(). The problem is that it will not work for automatic (local) variables. Actually, with a protected destructor you will not be able to declare local variables.
You probably mean calling PreDestroy() from the destructor of each subclass destructor. The problem will be not to forget it (you can assert that it has been called from ~Observer()) and if you have several levels of inheritance.
About your original solution:
Making Update() a callable virtual function seems to work, but it is technically wrong. While one thread is calling the virtual Update(), using the vtable pointer, another thread is calling ~Thing() and updating the vtable pointer to that of Observer(). The first thread holds the lock, but the second one does not, so you have a race.
My advice would be use option 2 unless you are very fond of automatic instances of subclasses of Observer.
If you are willing, you could try with templates:
template<typename O>
class ObserverPtr : Observer
{
public:
ObserverPtr(O *obj)
:m_obj(obj)
{}
void Update()
{
m_obj->Update();
}
~ObserverPtr()
{
PreDestroy();
delete m_obj;
}
private:
O *m_obj;
};
And then Thing will not derive from Observer.
You can also create alternative variants of this template:
to hold a reference to the real observer instead of a pointer (O &m_obj;). No use of delete.
to define the real observer as an actual member (O m_obj;). No dynamic allocations.
to hold a smart pointer to the real observer.
I think that unless you mandate to call Detach from the derived class destructor, it will not have an easy solution.
One solution which comes into my mind might be to utilize an extra "wrapper" which will take care of de-registration (and might actually do the registration as well).
Something like this (for example):
class ObserverAgent;
// the wrapper class - not virtual
class Observer
{
public:
Observer(Observable &subject, ObserverAgent &agent)
: _subject(subject), _agent(agent)
{
_subject.Attach(*this);
}
~Observer()
{
_subject.Detach(*this);
}
void Update()
{
_agent.Update();
}
private:
Observable &_subject;
ObserverAgent &_agent;
};
// the actual observer polymorphic object
class ObserverAgent
{
public:
ObserverAgent();
virtual ~ObserverAgent();
protected:
// only callable by the Observer wrapper
friend class Observer;
virtual void Update() = 0;
};
class Thing : public ObserverAgent
{
public:
virtual void Update();
};
The use is then indeed more convoluted:
Subject s;
{ // some scope
Thing t;
Observer o(s, t);
// do stuff
} // here first Observer is detached and destroyed, then Thing (already unregistered)
Note that you cannot Attach/Detach Thing (ObserverAgent) directly, only through Observer (because Observable takes the Observer, not the ObserverAgent).
Perhaps it could be possible to wrap it in a single class for simpler use (Agent being an inner class of the Observer), however then there might be problems with the lifetime of the agents (as the destruction of the Observer would have to be virtual again).
Why not expose the lock as protected in Observable? Observable::~Observable acquires the lock if it's not acquired already by this thread, then goes on with the cleanup. Meanwhile EVERY subclass of Observable acquires the lock in its dtor without further releasing it (which is only done in ~Observable itself).
Frankly, in this design the simplest and the most consistent solution seems to manually Detach() each Observer at the very start of the most derived class' destructor. I don't see how this can be automated, and since something has to be done at the dawn of destruction, why not detachment.
...Well, if we don't need to go deeper:
template<class Substance> struct Observer {
Observer(Observable &o): o(o) { o.attach(s); }
~Observer() { o.detach(s); }
Substance &subst() const { return s; }
private:
Observable &o;
Substance s;
};
struct ThingSubst { void update(); long stats(); };
typedef Observer<ThingSubst> Thing;
Observable o;
Thing thing(o);
std::cout << thing.subst().stats() << std::endl;
I have not been able to determine where a strange crash is coming from, but the fact it's not happening deterministically makes me suspect threading.
I have something like this:
class MyClass
{
MyClass() : mExit(false), mThread(&MyClass::ThreadMain,this)
{}
void ThreadMain()
{
unique_lock<mutex> lock(mMutex);
mCondition.wait(lock, [&] { return mExit; });
}
std::thread mThread;
std::mutex mMutex;
std::condition_variable mCondition;
bool mExit;
};
Obviously this is very simplified but I don't know for sure where the crash is happening yet so I want to ask if this setup can cause issues? What order is everything initialised for instance - is there a possibility ThreadMain can run before an instance of the class is fully constructed for example?
It looks like some examples I've seen online but I am not certain enough to say it's definitely safe or not.
The only issue I see is that class members are initialized in the order they are declared in the class. Since mThread comes before all of the other class members it could be possible that the thread is using them before they are ever initialized.
To fix this you can rearrange the class members but I do not like this approach. If someone else comes along and changes the order it could break the code. You should be able to let the thread get default initialized and then start the thread in the constructor body because at that point all class members have been initialized.
In addition to the member-construction-order-vs-thread-early-execution issue described by #NathanOliver, I would like to point out that the code will still exhibit undefined behaviour when using a virtual fuction in the place of ThreadMain.
Using a virtual function with your design is a problem as virtual functions are looked up from the vtable, and the pointer to the vtable isn't initialized until the constructor block has finished executing. Thus you end up with a thread that uses a pointer to a function that isn't initialized yet, which is UB.
The general solution to this kind of RAII thread-handler problem is to separate the initialization of the object from the execution of the thread, e.g., using a start function. This will also remove the dependency on the construction order of the members.
struct MyClass {
MyClass() : mExit(false) {}
void start() { mThread = std::thread{&ThreadMain, this}; } // Start function.
virtual void ThreadMain() = 0;
std::atomic<bool> mExit; // Not even bool is atomic :)
std::mutex mMutex;
std::condition_variable mCondition;
std::thread mThread;
};
This ensures that MyClass is constructed when starting the thread. Now, it is also possible to use polymorphism.
struct Derived : public MyClass {
virtual void ThreadMain() {
std::unique_lock<std::mutex> lock(mMutex);
mCondition.wait(lock, [&] { return mExit.load(); });
}
};
However, now the thread must be started using two statements instead of one, e.g., MyClass m; m.start();. To get around this we can simply create a wrapper class that executes the start function in the constructor body.
struct ThreadHandler {
ThreadHandler() { d.start(); }
Derived d;
};
Yes it could have bad behaviour since mThread may be started while the MyClass instance is not yet constructed.
My thumb rule: if I have to use this in the constructor, I doing something naughty ;).
I have a class that I'm trying to implement as an abstract class to maximize code reuse. However, a major part of the commonality between the two derived classes lies in the fact that each has a consumer and producer thread. I'm wondering if I can have each static member function call a virtual member function that does all of the underlying work.
Basically, is the following code allowed or am I doing something super hacky, or will the compiler yell/scream at me?
// in AbstractClass.h
class AbstractClass {
// some code here including constructors/destructors
protected:
virtual int Worker() = 0; // derived class provides implementation
private:
static void* Thread(void* args);
};
// in AbstractClass.cpp
static void* AbstractClass::Thread(void* args) {
AbstractClass myobject = static_cast<AbstractClass*>(args);
myobject->Worker();
}
Basically I'm wondering if the derived class "worker" will ever be called this way? Note that p_thread_create() is called with passing in the Thread() function.
Thanks for the help as I try to improve my understanding of inheritance and virtual functions and how I can use it to maximize code reuse.
Yes the code looks fine and your assumptions are correct. The purpose of virtual functions is that the most derived version of a function will be called no matter which superclass signature the method is called on.
Using pthreads and C++, the approach you are using is perfectly reasonable and not hackey. However, I would create the threads in a separate class which would contain the static class method. This would stop the threads from being mixed up in your derived classes.
struct ThreadManager
{
ThreadManager(AbstractWorker* worker)
{
mWorker = worker;
mThread = ThreadStart(threadFunc, this); /* made up thread code :) */
}
~ThreadManager()
{
ThreadStop(mThread);
}
static void* threadFunc(void* args)
{
ThreadManager* manager = static_cast<ThreadManager*>(args);
manager->mWorker->Work();
}
AbstractWorker* mWorker;
Thread mThread;
}
Note that when using pthreads a static function is actually required.
Developing on Ubuntu using Eclipse/gcc with -std=c++0x.
I seem to be having an issue with object slicing, that doesn't fall under the other questions I've seen here. I have a very simple base class / child class inheritance model. Base class has one pure virtual function which obviously the child implements:
class Parent{
public:
Parent();
virtual ~Parent();
virtual void DoStuff() = 0;
};
class Child : public Parent{
public:
Child();
virtual ~Child();
virtual void DoStuff(); //Child can have "grandchildren"
};
What I want is to have a queue where I can store these objects for processing by a worker thread. I know I should be storing pointers, or else I'd guarantee slicing. So, in the class ("Processor") which does this I have:
typedef queue<Parent*> MYQUEUE; //#include <queue>
static MYQUEUE myQueue;
//Call this after creating "Child c;" and passing in &c:
void Processor::Enqueue(Parent* p)
{
myQueue.push(p);
}
void* Process(void* args) //function that becomes the worker thread
{
while(true)
{
if(!myQueue.empty())
{
Parent* p = myQueue.front();
p->DoStuff();
myQueue.pop();
}
}
return 0;
}
What then happens is that the program crashes, saying "pure virtual method called", as if the inheritance/polymorphism isn't working correctly. I know the inheritance is set up correctly, because as I test I confirmed this works:
Child c;
Parent* p = &c;
p->DoStuff();
Any guidance greatly appreciated!
If you are passing the object to a worker thread, you can't create it on the stack. By the time the worker thread invokes it, the parent thread has likely left that function and destroyed the object. You need to dynamically allocate (perhaps via new) it in the parent thread and only free (delete) it in the worker thread after you're done with it.
As another note, you need locking around your queue accesses if the parent is able to enqueue a job while the worker is running.
The error means that the object pointed to by p at the point of the call has type Parent. How it got that way depends on the code that you haven't shown.
duplicate of: "pure virtual method called" when implementing a boost::thread wrapper interface
I am trying to create a more object oriented version of the threads using boost threads.
So I created a Thread class:
class Thread {
public:
Thread() {}
virtual ~Thread() { thisThread->join(); }
void start() { thisThread = new boost::thread(&Thread::run, this); }
virtual void run() {};
private:
boost::thread *thisThread;
};
this class creates the thread in start()
like this:
thisThread = new boost::thread(&Thread::run, this);
The problem is that when I create a class that overwrites the run() method, the run() method from Thread is call by the thread instead of the new run() method
for example I have a class that extends Thread:
class CmdWorker: public Thread {
public:
CmdWorker() : Thread() {}
virtual ~CmdWorker() {}
void run() { /* deosn't get called by the thread */ }
};
when I do
Thread *thread = new CmdWorker();
thread.start(); //---> calls run() from Thread instead of run() from CmdWorker
but just to be more clear:
thread.run(); calls the correct run from CmdWorker, (run() is virtual from Runnable)
Any idea why this happens or how it can be fixed ?
NOTE:
I created a function (that has nothing to do with the Thread class)
void callRun(Thread* thread) {
thread->run();
}
and changed the thread creation to:
thisThread = new boost::thread(callRun, this);
when debugging I noticed that the thread pointer is pointing to a object of type Thread instead of CmdWorker
EDIT:
testcase code at: http://ideone.com/fqMLF
and http://ideone.com/Tmva1
Object seems to be sliced (but this is strange since pointers are used)
didn't manage to add boost to it
The answer is in that question:
"pure virtual method called" when implementing a boost::thread wrapper interface
Basically, when the boost::thread object begins running, the object it was run against had the
time to be deleted.
You have to implement a join method that you call manually before destroying the object.
when debugging I noticed that the thread pointer is pointing to a
object of type Thread instead of CmdWorker
Maybe the CmdWorker object is sliced (i.e. copied by value) into a Thread object somewhere in your code?
Do you get the same behaviour with a minimal test case?
By doing &Thread::Run on a non-virtual function, you are forcing any class that derives from Thread to use the function specified in the Thread base class. Try making Thread::Run a virtual void and see if that fixes your issue.
From reading your updates, you're calling delete in the main thread, while the thread is starting in the other. Depending on the race between the destructor and the invocation of run, it will either:
Crash before it starts, because the vtable is completely destroyed
Call the Thread::run (which is pure virtual, and crashes with a pure virtual thunk)
Call the correct function, which is the derived class run()
If you add a call to sleep(1) after you call start, but before you call delete, you'll find that it works as you expect.