C ++继承了用于Raspberry Pi g ++的类vtable损坏?

时间:2016-09-28 19:41:18

标签: c++ multithreading constructor race-condition vtable

我有一些代码可以在Linux(x86_64)和Raspberry Pi上运行。代码在Linux上运行正常,但在RPi上与SIGSEGV崩溃。派生的方法似乎没有填充vtable,我想知道它是否是由于竞争条件造成的?

以下是实现线程的类:

class Runnable {
      public:
        Runnable() {}
        virtual ~Runnable() {}

        // Starts the thread & execute the doWork() method.
        void start() {
            thread = std::thread(&Runnable::doWork, this);
        }


        // Stop the thread if running
        virtual void stop() = 0;

        // Joins the thread, blocks until the thread has finished.
        void join() {
            if (thread.joinable()) { thread.join(); }
        }

      protected:
        std::thread thread; ///< the thread used by this class

        /**
         * @brief The method that does work. This will be called when the thread is started.
         * The implementation should not return until stop() is called (or is finished with work).
         * This is in protected scope as it should not be called except from the start() method.
         */
        virtual void doWork() = 0;    
    };

template <typename VIRTUAL_CLASS_TYPE>
class SomeRunner : public Runnable {
    public:
        SomeRunner() {}
        virtual ~SomeRunner() {
            // do not delete classPtr, as a framework we are using deletes it for us
        }

    virtual void doWork() { 
        // do some work
        classPtr = new VIRTUAL_CLASS_TYPE();

        // notify main thread that we have created classPtr
        // this is done via a condition variable & mutex
        notifyIsReady();

        // do some more work
    }

    virtual void stop() {
       // tell thread to stop work
    }

    VIRTUAL_CLASS_TYPE *getClassPtr() {
        return classPtr;
    }

    protected:
        VIRTUAL_CLASS_TYPE *classPtr = nullptr;
}


// Within InterfaceLibrary.a
class BaseClass {
    public:
        BaseClass() {}
        virtual ~BaseClass() {}

        virtual void someMethod() = 0;
}


//Within ImplementationLibrary.a:
class ImplClass : public BaseClass {
    public:
        ImplClass() : BaseClass() {}
        virtual ~ImplClass() {}

        virtual void someMethod() {
            // do something here
        }
}


// within main application project

class ClassThatCausesDump {
    // ...
    void someMethod(BaseClass *bc) {
        bc->someMethod();
    }
}



bool                                isReady = false;
std::mutex                           mutexIsReady;
std::condition_variable              cvIsReady;

void notifyGlsIsReady() {
    std::unique_lock<std::mutex> lock(mutexIsReady);
    isReady = true;
    lock();
    cvIsReady.notify_one();
}


int main(int argc, char **argv) {
    // ...
    SomeRunner<ImplClass> runner;
    runner.start();

    // main blocks until notified that the ImplClass has been created by runner
    std::unique_lock<std::mutex> isReadyLock(mutexIsReady);
    cvIsReady.wait(isReadyLock, [] {return isReady;});


    ClassThatCausesDump dump;
    dump.someMethod(runner.getClassPtr()); // this triggers the core dump on RPi

变量classPtr虽然作为BaseClass传递,但应调用派生的someMethod()。但是,当我使用gdb运行时,我发现程序在someMethod()内的ClassThatCausesDump调用时崩溃了。它尝试在0x000000执行指令。

该程序适用于功能强大的多核OSX机器中的Linux VM,但不适用于RPi。我清理了一切然后重新编译,然后它突然在RPi上工作。然后我再次清理以确保它不是侥幸,然后它又恢复了崩溃(它从未在Linux上崩溃)。这让我觉得在类似的线程中创建类的方式可能有些有趣吗?

请问任何想法?

编辑:

我不认为这与线程有关,因为如果在doWork()方法内完成,则可以调用违规的虚函数。

virtual void doWork() { 
    // do some work
    classPtr = new VIRTUAL_CLASS_TYPE();

    VIRTUAL_CLASS_TYPE *ptr = getClassPtr();
    ptr->someMethod(); // this is ok and does not crash
    // This next line is only here for testing because we know that VIRTUAL_CLASS_TYPE is of type ImplClass!
    BaseClass *bc = (BaseClass*)ptr; 
    bc->someMethod(); // this crashes

    // notify main thread that we have created classPtr
    // this is done via a condition variable & mutex
    notifyIsReady();

    // do some more work
}

0 个答案:

没有答案