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(),它调用纯虚函数()。这是带有额外输出的程序:

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()则在析构函数中调用将使用 Thread 的 vtable 而不是 A 启动 boost 线程,因为在 C++ 中,在析构函数的点上,vtable 匹配析构函数类型的范围,而不是最派生的虚表。

于 2010-07-01T18:07:12.207 回答