2011-09-12 56 views
5

重複的:"pure virtual method called" when implementing a boost::thread wrapper interface提升線程破壞多態性

我試圖創建一個使用升壓線程的線程更多的面向對象版本。

所以我創建了一個Thread類:

class Thread { 
public: 
    Thread() {} 
    virtual ~Thread() { thisThread->join(); } 

    void start() { thisThread = new boost::thread(&Thread::run, this); } 

    virtual void run() {}; 

private: 
    boost::thread *thisThread; 
}; 

這個類中創建啓動線程() 這樣的:

thisThread = new boost::thread(&Thread::run, this);

的問題是,當我創建一個類,覆蓋run()方法,從Thread的run()方法是由線程調用而不是新的run()方法

,比如我有繼承Thread類:

class CmdWorker: public Thread { 
public: 
    CmdWorker() : Thread() {} 
    virtual ~CmdWorker() {} 

    void run() { /* deosn't get called by the thread */ } 
}; 

當我做

Thread *thread = new CmdWorker(); 
thread.start(); //---> calls run() from Thread instead of run() from CmdWorker 

但爲了更加清晰:

thread.run(); calls the correct run from CmdWorker, (run() is virtual from Runnable) 

任何想法,爲什麼出現這種情況或如何修復?

注: 我創建了一個函數(即具有無關Thread類)

void callRun(Thread* thread) { 
    thread->run(); 
} 

,改變了線程創建於:

thisThread = new boost::thread(callRun, this); 

當調試我注意到thread指針指向Thread類型的對象而不是CmdWorker

編輯:

測試用例代碼爲:http://ideone.com/fqMLFhttp://ideone.com/Tmva1

對象似乎切片(但是這是奇怪的,因爲使用指針)

沒能提振添加到它

+0

這個問題我不清楚! – Nawaz

+1

代碼不足。我看不出你會如何使用這種構造。 –

+2

FYI'std :: thread'即將到達。無論如何,boost :: thread'究竟有什麼問題? – spraff

回答

1

這樣做&Thread::Run在非虛函數上,您迫使從Thread派生的任何類使用Thread基類中指定的函數。嘗試讓Thread ::運行一個虛擬的void,看看是否解決了你的問題。

+1

運行是從Runnable虛擬的 – Ha11owed

+0

但不是來自線程。 – Michael

+3

@Michael:在C++中,只要成員函數簽名匹配(他們在這種情況下),'virtual'就會從基類繼承。將'Thread :: run'聲明爲'virtual'將是多餘的。 – ildjarn

3

調試時我注意到,螺紋指針指向型螺紋,而不是CmdWorker的 對象

也許CmdWorker對象被切片(即,由值複製)到一個Thread對象某處你的代碼?

你是否得到了與最小測試用例相同的行爲?

+0

是的我得到了與測試案例相同的行爲 – Ha11owed

2

從閱讀您的更新,您在主線程中調用delete,而線程在另一個線程中啓動。根據析構函數和run調用之間的競爭,這將:

  1. 崩潰開始之前,因爲虛函數表被完全破壞
  2. 調用的線程運行::(這是純虛擬的,採用了純虛擬的thunk崩潰)
  3. 調用正確的函數,這是派生類的run()

如果添加了調用sleep(1)你打電話開始後,但你叫delete之前,你會發現它起作用了你期望的。

+0

我簡化了示例並刪除了任何鎖+檢查。 也在析構函數中我做了一個join(),所以它等待線程完成。 正如我之前提到的,run()從線程被調用。 – Ha11owed

+3

@ Ha11owed如果在'Thread'的析構函數中添加一個連接,那麼在調用連接時,大部分派生類已經被銷燬,並且它的vtable條目不再存在。 –

+0

我現在明白了 沒有注意到 – Ha11owed