3

オブジェクトの作成時にスレッドを実行し、オブジェクトが削除されるとスレッドを停止するクラスを作成しようとしています。

class MyThread : public boost::thread {

public:

    MyThread() : bAlive(true) { 
        boost::thread(&MyThread::ThreadFunction,this);
    }

    ~MyThread() {
        {
            boost::unique_lock<boost::mutex> lock(Mutex);
            bAlive=false;
        }
        ConditionVariable.notify_one();
        join();
    }

private:

    volatile bool bAlive;
    boost::mutex Mutex;
    boost::condition_variable ConditionVariable;

    void ThreadFunction() {
        boost::unique_lock<boost::mutex> lock(Mutex);
        while(bAlive) {
            ConditionVariable.timed_wait(lock,boost::get_system_time()+ boost::posix_time::milliseconds(MAX_IDLE));

            /*******************************************
            * Here goes some code executed by a thread * 
            *******************************************/

        }
    }

};

理論的には、スレッドが終了する必要があるとすぐにスレッドをウェイクアップしたいので、Sleep の代わりに timed_wait を使用する必要がありました。このクラスのオブジェクトを削除しようとするまで、これは正常に機能します。ほとんどの場合、正常に削除されますが、場合によっては、condition_variable.hpp、thread_primitives.hpp、または crtexe.c のいずれかでエラーが発生します。「解放された後、3da804 で変更された Free Heap block 3da7a8」と通知されることもあれば、通知されないこともあります。はい、私は timed_wait の偽のウェイクアップを認識しています。この場合、それは重要ではありません。問題の原因を教えてください。私は何を間違っていますか?

4

1 に答える 1

1

あなたがやろうとしていることはわかりますが、期待どおりに動作しません:

MyThread foo;

デフォルトでは、boost::thread が構築されます (MyThread は boost::thread から派生しているため)。デフォルトのコンストラクターは、Not-a-Thread を参照する boost::thread インスタンスを作成します。

MyThread() {
    boost::thread(&MyThread::ThreadFunction,this);
}

実際には別のスレッドを作成しており、返されたオブジェクト (有効なスレッド) を無視しています。

~MyThread() {
    // ...
    join();
}

次に、デフォルトで構築されたスレッド(destructor 内で例外をスローする)に参加しようとしていますが、実際に作業を行うスレッドに参加することはありません。


まず、boost::thread から派生させないでください。代わりにメンバー変数を作成します。

class MyThread {
// ...
private:
    // ...
    boost::thread _thread;
};

コンストラクターで、スレッドを作成してそのメンバー変数に割り当てます。

MyThread() {
    _thread = boost::thread(&MyThread::ThreadFunction,this);
}

そして、デストラクタでその join() を呼び出します。

~MyThread() {
    // ...
    _thread.join();
}

これで問題が解決するはずです。


ただし、オブジェクトが破棄されたときに単にスレッドを終了したい (そして実行中にスレッドを起こす必要がない) 場合は、別の方法を使用できます。ミューテックスと条件変数を削除し、代わりに割り込みを使用してください。これにより、 sleep() が例外をスローするため、キャッチする必要があります。

void ThreadFunction() {
    try {
        for(;;) {
            boost::this_thread::sleep(boost::posix_time::milliseconds(MAX_IDLE));
            // Here goes some code executed by a thread
        }
    } catch( const boost::thread_interrupted& e ) {
        // ignore exception: thread interrupted, exit function
    }
}

これにより、スレッドが中断されるとすぐに ThreadFunction が終了します。スレッドを毎サイクルスリープさせる必要がない場合は、 に置き換えることができますboost::this_thread::interruption_point()。スレッドが中断された場合、これは例外をスローします。

これで、デストラクタでスレッドを単純に中断できます。

MyThread::~MyThread() {
    _thread.interrupt();
    _thread.join();
}
于 2012-11-10T17:38:33.913 に答える