2010-10-01 88 views
1

我剛剛開始學習C++,我正在嘗試使Thread類具有Java Thread類的基本功能。我想要做的是創建一個你繼承的類,編寫一個Run方法(在基類中是純虛擬的)創建子類的對象,調用start方法,並且你有線程。虛擬方法和這個指針

的問題是,在路上我使用C++調度沒有正確完成, - 就像運行函數不是虛擬的,基類的run方法被調用。

這裏是頭

#ifndef _THREAD_H_ 
#define _THREAD_H_ 

#include <pthread.h> 

class Thread { 
public: 
    Thread(); 

    void Start(); 

    ~Thread(); 

protected: 
    virtual void Run() = 0; 

private: 
    static void *RunWrapper(void *); 

    pthread_t thread; 
}; 

#endif 

實施

#include "thread.h" 

#include <pthread.h> 

Thread::Thread() { 
} 

void Thread::Start() { 
    pthread_create(&thread, NULL, Thread::RunWrapper, (void *) this); 
} 

void *Thread::RunWrapper(void *arg) { 
    Thread *t = (Thread *) arg; 
    t->Run(); 
    return arg; 
} 

Thread::~Thread() { 
    pthread_join(thread, NULL); 
} 

而這實際上是嘗試做一些事情

#include <iostream> 

#include "thread.h" 

class MyThread : public Thread { 
protected: 
    void Run() { 
    std::cout << "The thread is runned" << std::endl; 
    } 
}; 

int main(void) { 
    MyThread thread; 
    thread.Start(); 
    return 0; 
} 

我不斷收到了錯誤的文件的代碼最近10小時是:

pure virtual method called 
terminate called without an active exception 
+0

如果您確實想要複製Java功能,請改爲複製java.util.concurrent包。它具有更先進的多線程概念,如執行者,期貨,鎖和互斥鎖。但是,如果你走得很遠,只需使用boost:它已經實現了所有這些東西。 – 2010-10-01 00:46:51

回答

5

的問題是,在主要的MyThread的對象,一旦被破壞的主函數返回,這可能發生在新線程真正開始調用其Start方法之前。

作爲銷燬過程的一部分,在調用基類析構函數之前,vtable將被重置爲基類的vtable,因此當以後運行RunWrapper調用時,它將觸發純虛方法錯誤。在被銷燬的對象上調用方法會導致未定義的行爲,所以可能發生任何事情;這種行爲是C++編譯器如何實現析構函數和堆棧分配的一個偶然事件。

+0

是的,這是問題所在。非常感謝!當學習一種新的語言時,人們認爲所有的問題都是由語言產生的:)。 – 2010-10-01 00:28:27

0

不能肯定什麼,直接導致了錯誤,但你在做什麼不好:您MyThread的對象可以走出去的範圍你的線程訪問它。完全有可能範圍消失,指針在線程開始處理時無效。

嘗試在堆中分配的對象,看看它是否工作(當時,假設它確實弄清楚如何釋放對象,當線程完成)。

哦,你會想下一個出口您的應用程序(從main返回),直到你的線程也做...

+0

我使用同步機制修復了它。謝謝! – 2010-10-01 00:29:35

+0

那麼,它不會完全消失,因爲在'Thread ::〜Thread()'中調用了'pthread_join'。但是,當「Thread ::〜Thread」運行時,對象已經失去了作爲派生類的身份(派生析構函數已經運行) - 在銷燬期間,虛擬方法被稱爲非虛擬方法。 – 2010-10-01 00:29:42

-2

問題是您正在調用屬於Thread類的Start。然後這個方法調用Run,它將調用Thread類的Run方法。不幸的是,你不能從基類中調用重寫的方法。

+1

這是不正確的;這正是虛擬方法的作用。 – Nick 2010-10-01 00:21:21

+0

你不能從基類方法中調用它們。 – 2010-10-01 00:27:34

+0

我可以在子類上調用Run,因爲我使用了一個指針並且該方法是虛擬的。 – 2010-10-01 00:30:25