【问题标题】:boost thread destroys polymorphismboost线程破坏多态性
【发布时间】:2011-09-12 17:59:13
【问题描述】:

重复:"pure virtual method called" when implementing a boost::thread wrapper interface

我正在尝试使用 boost 线程创建一个更面向对象的线程版本。

所以我创建了一个线程类:

class Thread {
public:
    Thread() {}
    virtual ~Thread() { thisThread->join(); }

    void start() { thisThread = new boost::thread(&Thread::run, this); }

    virtual void run() {};

private:
    boost::thread *thisThread;
};

这个类在 start() 中创建线程 像这样:

thisThread = new boost::thread(&Thread::run, this);

问题是,当我创建一个覆盖run() 方法的类时,Thread 中的run() 方法被线程调用,而不是新的run() 方法

例如,我有一个扩展 Thread 的类:

class CmdWorker: public Thread {
public:
    CmdWorker() : Thread() {}
    virtual ~CmdWorker() {}

    void run() { /* deosn't get called by the thread */ }
};

当我这样做时

Thread *thread = new CmdWorker();
thread.start(); //---> calls run() from Thread instead of run() from CmdWorker

但为了更清楚:

thread.run();  calls the correct run from CmdWorker, (run() is virtual from Runnable)

知道为什么会发生这种情况或如何解决吗?

注意: 我创建了一个函数(与 Thread 类无关)

void callRun(Thread* thread) {
    thread->run();
}

并将线程创建更改为:

thisThread = new boost::thread(callRun, this);

在调试时我注意到thread 指针指向的是 Thread 类型的对象,而不是 CmdWorker

编辑:

测试用例代码:http://ideone.com/fqMLFhttp://ideone.com/Tmva1

对象似乎被切片了(但这很奇怪,因为使用了指针)

没能增加动力

【问题讨论】:

  • 这个问题我不清楚!
  • 没有足够的代码。我看不出你会如何使用这种结构。
  • 仅供参考 std::thread 即将到来。 boost::thread到底有什么问题?
  • 你在构造函数中碰巧调用了start吗?
  • @Hallowed:好的,我设法让它在我的机器上编译,令人惊讶的是,我观察到了你的行为。让我开始吧。

标签: c++ boost boost-thread


【解决方案1】:

答案就在那个问题中:

"pure virtual method called" when implementing a boost::thread wrapper interface

基本上,当 boost::thread 对象开始运行时,它所针对的对象具有 时间被删除。

您必须在销毁对象之前实现手动调用的join 方法。

【讨论】:

    【解决方案2】:

    调试时我注意到线程指针指向一个 Thread 类型的对象而不是 CmdWorker

    也许CmdWorker 对象在您的代码中某处被切片(即按值复制)为Thread 对象?

    用最少的测试用例获得相同的行为吗?

    【讨论】:

      【解决方案3】:

      通过对非虚拟函数执行&Thread::Run,您将强制任何派生自 Thread 的类使用 Thread 基类中指定的函数。尝试制作 Thread::Run 虚拟 void 并查看是否可以解决您的问题。

      【讨论】:

      • @Michael :在 C++ 中,virtual 是从基类继承的,只要成员函数签名匹配(在这种情况下就是这样做的);将Thread::run 声明为virtual 将是多余的。
      【解决方案4】:

      通过阅读您的更新,您在主线程中调用 delete,而线程在另一个线程中启动。根据析构函数和run 调用之间的竞争,它会:

      1. 在启动前就崩溃了,因为 vtable 被完全破坏了
      2. 调用 Thread::run(它是纯虚拟的,会因纯虚拟 thunk 而崩溃)
      3. 调用正确的函数,即派生类run()

      如果您在调用 start 之后,但在调用 delete 之前添加对 sleep(1) 的调用,您会发现它按预期工作。

      【讨论】:

      • 我简化了示例并删除了所有锁和检查。同样在析构函数中我做了一个 join() 所以它等待线程完成。正如我之前提到的,来自线程的 run() 被调用。
      • @Ha11owed 如果在Thread 的析构函数中添加连接,那么在调用连接时,派生最多的类已经被销毁,并且它的vtable 条目不再存在。
      • 我明白了,现在没注意到
      猜你喜欢
      • 2011-01-15
      • 1970-01-01
      • 2011-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-20
      • 1970-01-01
      • 2019-09-09
      相关资源
      最近更新 更多