我有一個具有受保護構造函數的基類IRunnable,因此不能創建基類的任何實例。該類有一個純虛擬方法run(),它必須由派生類實現。我將IRunnable *的指針傳遞給某種類似java的Executor,該Executor控制多個線程,並將這些Runnables分配給它們。 我的問題是,當這樣一個IRunnable *指針指向IRunnable派生類的一個對象,它位於另一個線程的堆棧上時,它被分配給一個工作線程,我無法確定,派生的對象是在工作線程仍在使用它時不會被銷燬,因爲線程上具有該對象的線程可能會離開創建該對象的範圍。 例如:防止派生類被破壞
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);
}
};
我實現了基類IRunnable引用計數,而我做的析構函數阻塞調用的最後一個線程使用它與它註銷時纔會回來。問題是,首先調用派生類get的析構函數,因此在調用阻塞調用的基類被破壞之前,對象將被部分地破壞。 在上面的例子中,我得到以下運行時錯誤:
pure virtual method called
terminate called without an active exception
如果我的.submit()調用後插入一些微秒的usleep,它會工作,因爲線程將可運行完成,在它被破壞之前
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);
}
[...]
我該怎麼辦?
我知道在堆中分配的對象不會被銷燬,直到調用一個明確的刪除,但這並不能解決我的問題。 共享指針是什麼意思? – user2950911
爲什麼它不能解決你的問題?該對象在工作完成之前不會被刪除? – Peter
好吧,我寧願有一個解決方案,不依賴於程序員只使用動態分配,我希望它也可以使用堆棧中的對象。你當然是對的,我的阻塞析構函數會使給定的例子同步,但對我來說這完全沒問題,這個例子只是爲了顯示發生錯誤的情況,而不是顯示一個案例如何正確使用執行器 – user2950911