форсированная нить разрушает полиморфизм - PullRequest
5 голосов
/ 12 сентября 2011

дубликат: "чистого виртуального метода, вызываемого" при реализации интерфейса оболочки boost :: thread

Я пытаюсь создать более объектно-ориентированную версию потоков, используя потоки boost.

Итак, я создал класс Thread:

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(), метод run() из Thread вызывается потоком вместо нового run() метода

, например, у меня есть класс, который расширяетТема:

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/fqMLF и http://ideone.com/Tmva1

Объект выглядит нарезанным (но это странно, поскольку используются указатели)

не удалось добавить повышение

Ответы [ 4 ]

4 голосов
/ 12 сентября 2011

Ответ на этот вопрос:

«чисто виртуальный метод вызван» при реализации интерфейса boost :: thread

По сути, когда объект boost :: thread начинает работать, объект, с которым он работал, имел время быть удаленным.

Вам необходимо реализовать метод join, который вы вызываете вручную перед уничтожением объекта.

3 голосов
/ 12 сентября 2011

при отладке я заметил, что указатель потока указывает на объект типа Thread вместо CmdWorker

Возможно, объект CmdWorker разрезан (т.е. скопирован по значению) вThread объект где-нибудь в вашем коде?

У вас такое же поведение с минимальным тестовым набором?

2 голосов
/ 12 сентября 2011

Читая ваши обновления, вы вызываете delete в главном потоке, а поток запускается в другом.В зависимости от расы между деструктором и вызовом run, он будет либо:

  1. Сбой перед началом, потому что виртуальная таблица полностью уничтожена
  2. Вызовите поток ::run (который является чисто виртуальным и падает с чисто виртуальным потоком)
  3. Вызовите правильную функцию, которая является производным классом run ()

Если вы добавите вызов к sleep(1) после того, как вы позвоните start, но прежде чем позвонить delete, вы обнаружите, что он работает так, как вы ожидаете.

1 голос
/ 12 сентября 2011

Делая &Thread::Run для не виртуальной функции, вы заставляете любой класс, производный от Thread, использовать функцию, указанную в базовом классе Thread. Попробуйте сделать Thread :: Run виртуальным void и посмотрите, решит ли это вашу проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...