I have a base class IRunnable with a protected constructor, so that no instances of the base class can be created. The class has a pure virtual method run(), which has to be implemented by derived classes. I am passing pointers of IRunnable * to some kind of java-like Executor, which controls a number of threads, and assigns those Runnables to them. My Problem is, when such a IRunnable * pointer, pointing to an object of a derived class of IRunnable, which lies on a stack of another Thread, is assigned to a worker Thread, i can not be sure, that the derived Object is not destroyed while the worker thread is still using it, since the thread that has the object on its thread could leave the scope where the object was created. For Example:
int main(void)
{
CExecutor myExecutor(...);
for (UInt32 i = 0; i < 2; i++)
{
derivedRunnable myRunnable1; //will be destroyed after each loop iteration
myExecutor.submit(myRunnable1);
}
}
class derivedRunnable : public IRunnable
{
public:
derivedRunnable(const char * name = NULL) : IRunnable(name) {}
~derivedRunnable() {}
void run(void)
{
for (UInt32 i = 0; i < 100; i++)
{
char name [256] = {"\0"};
pthread_getname_np(pthread_self(), name, 255);
printf("%s in step %d\n", name, i);
}
fflush(stdout);
}
};
I implemented a reference count in the base class IRunnable, and I do a blocking call in the destructor that will only come back when the last thread using it unregisters with it. The problem is, the destructor of the derived class get's called first, so the object will be partially destructed before base class destructed with the blocking call is called.
In the above example, i get the following runtime error:
pure virtual method called
terminate called without an active exception
If I insert a usleep of some usec after the .submit() call, it will work, because the thread will be finished with the runnable, before it gets destroyed
class IRunnable
{
friend class CThread;
friend class CExecutor;
private:
CMutex mutx;
CBinarySemaphore sem;
UInt32 userCount;
[...]
virtual void run(void) = 0;
IRunnable(const IRunnable & rhs); //deny
IRunnable & operator= (const IRunnable & rhs); //deny
void registerUser(void)
{
mutx.take(true);
if (0 == userCount++)
sem.take(true);
mutx.give();
}
void unregisterUser(void)
{
mutx.take(true);
if (0 == --userCount)
sem.give();
mutx.give();
}
protected:
IRunnable(const char * n = NULL)
:mutx(true,false)
,sem(true,false)
,userCount(0)
{
setName(n);
}
~IRunnable()
{
sem.take(true);
}
[...]
What could I do?