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 * 
            *******************************************/

        }
    }

};

从理论上讲,我想在线程需要完成时立即唤醒它,所以我不得不使用 timed_wait 而不是 Sleep。在我尝试删除此类的对象之前,这工作正常。在大多数情况下,它会正常删除,但偶尔会在 condition_variable.hpp、thread_primitives.hpp 或 crtexe.c 中导致错误。有时我会收到通知“释放堆块 3da7a8 在 3da804 被释放后修改”,有时我不是。是的,我知道 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();
}

然后尝试加入默认构造的线程(在析构函数中引发异常),而您永远不会加入实际完成工作的线程。


首先,不要从 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 回答