我有一些代码可以在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
}