6

私はスレッドに関連するものを一元化する小さなラッパーを持っています:

class Thread {
protected:
    boost::thread *m_thread;

    virtual void work() = 0;

    void do_work() {
        work();
    }

public:
    Thread() : m_thread(NULL) {}
    virtual ~Thread() {
        catch_up();
        delete m_thread;
    }

    inline void catch_up() {
        if(m_thread != NULL) {
            m_thread->join();
        }
    }

    void run() {
        m_thread = new boost::thread(boost::bind(&Thread::do_work, boost::ref(*this)));
    }
};

私がそれを実装するとき、次のように言います:

class A : public Thread {
    void work() {}
};

で :

A a; a.run();

かなりの「純粋仮想メソッドと呼ばれる」が表示されたランタイム終了が発生しました。これはboost::bind引数だと思いますが、「仮想の純粋な実装を使用する」と言う方法がわかりません...

よろしくお願いします。

よろしく、

ミスターミステール

4

2 に答える 2

6

クラッシュは、プログラムがすぐに終了した場合にのみ発生します。新しく開始されたスレッドがスケジュールされる前に、終了するクラス A のデストラクタを呼び出し、スレッドのデストラクタを呼び出します。次に、スレッドは仮想関数を呼び出しますが、クラス A は存在しないため、スレッドの do_work() を呼び出そうとします。これにより、純粋な仮想 work() が呼び出されます。追加の出力を含むプログラムは次のとおりです。

run() started 
run() ended
~A() started
~A() ended
~Thread() started
catch_up() started
do_work() started
pure virtual method called

標準的には、オブジェクトへの参照 ( boost::ref(*this)) を使用してスレッドから do_work() を呼び出したときに、オブジェクトの有効期間が既に終了している (デストラクタ呼び出しが開始されている) ため、これは未定義の動作だと思います。

解決策: オブジェクトを破棄する前にスレッドを実行させます。

A a; a.run();
a.catch_up();

または、boost.thread のドキュメントにあるように、「Boost.Thread のユーザーは、参照先のオブジェクトが新しく作成された実行スレッドよりも長く存続することを確認する必要があります」。

于 2010-07-01T19:02:03.073 に答える
1

私はここで手足を出していますが、問題は Thread デストラクタにあると思われます:

virtual ~Thread() { 
    catch_up(); 
    delete m_thread; 
} 

スレッドがまだ開始されていない場合、catch_up()デストラクタを呼び出すと、A ではなくスレッドの vtable を使用してブースト スレッドが開始されます。C++ では、デストラクタの時点で vtable がデストラクタのタイプのスコープと一致し、最も派生したものではありません。 vtable.

于 2010-07-01T18:07:12.207 に答える