Reputation: 1363
This problem seems to be related to threads and running the program very quickly. I have 2 classes, ThreadParent
and ThreadChild
where one inherits from another. ThreadParent
creates a thread and runs the function func
, declared as static to circumvent pointer problems. I do however want that the inherited classes such as ThreadChild
decide what the thread exactly does so func
calls the virtual function Do
.
When creating a ThreadChild
object however and immediately running the thread calls ThreadParent::Do
once at the start, and all following calls are ThreadChild::Do
. Interestingly, when I wait a bit before calling Do
, it does not happen.
Is there a better solution than to wait a bit? And more importantly, why does this happen?
Here is a small, but complete example. It creates a ThreadChild
object which executes Do
every 200ms. The program ends after 1s (waiting for an enter press).
#include <iostream>
#include <windows.h>
#include <thread>
// The parent class
class ThreadParent {
protected:
bool _loopThread; //setting this to false should end the thread
std::thread _thread; //the thread
public:
// Basic constructor
ThreadParent(ThreadParent* child)
: _loopThread(true),
_thread(func, child, &_loopThread) {}
// Stops the thread and waits for it to finish
void StopThread() {
_loopThread = false;
_thread.join();
}
protected:
// The function the thread will be running (static because of pointer issues)
static void func(ThreadParent* child, bool* loopThread) {
//Sleep(10); //<- uncomment to solve the problem?
while (*loopThread) {
child->Do(); // Do is called every 200ms
Sleep(200);
}
}
// The function which is called repeatedly until _loopThread is set to false
virtual void Do() {
std::cout << "Parent call\n";
}
};
// The child class
class ThreadChild : public ThreadParent {
public:
// Basic constructor
ThreadChild()
: ThreadParent(this) {}
protected:
// Redefines Do() with another message
void Do() {
std::cout << "Child call\n";
}
};
// The program
int main() {
ThreadChild thread; // Create and run the thread
Sleep(1000); // Run the thread for 1s
thread.StopThread(); // End it
std::cout << "Press <enter> to terminate...";
std::cin.get(); // Wait for user to end program
return 0;
}
Output:
Parent call
Child call
Child call
Child call
Child call
Press <enter> to terminate...
Upvotes: 3
Views: 1700
Reputation: 158
When the derived class is instantiated, first the base class constructor is called and the vtable pointer vptr
is initialized to the base class vtable, which holds a pointer to the ThreadParent::Do
. Only when the derived class constructor runs, the vtable pointer vptr
is over-written (made to point) to the dervied class vtable, which holds a pointer to ThreadChild::Do
.
As a result, calling a virtual method from base class constructor will always call the base class implementation and not the derived class over-ridden method.
This faq explains the same in greater detail
Upvotes: 0
Reputation: 17415
During construction, the baseclass subobject is constructed before the derived class. Inside the baseclass body, the dynamic type is actually that of the baseclass, so dynamic function dispatches (virtual function calls) will call the according function of the baseclass. Depending on the timing, you will thus see either function being called.
In order to fix that, just start the thread explicitly in a second initialization function that is called after the construction is complete.
BTW: The static
function is a red herring, you don't avoid any mistakes. Also, it's typically a bad idea to create thread hierarchies. Rather, your class instances represent tasks or jobs, which may or may not be executed in a separate thread. Tightly coupling these objects to a thread may be a bad idea. Also, the way you pass a pointer to the baseclass constructor seems fragile, because as it creates a dependency that shouldn't exist in the first place.
Upvotes: 3