QThread::wait() causing crash
Greetings!
I'm having a problem with my QThread classes. I based them on the Qt Example Mandlebrot (I'm also doing an long rendering process). I extracted the core mutex and waitCondition syncronization that was in the renderThread into it's own class (which I call InfiniteThread) and then I sub-class this to specialize what task that thread will perform.
Problem is, whenever an instance of InfiniteThread is destroyed and the destructor gets called I get a SIGABRT and the following console output:
Quote:
pure virtual method called
terminate called without an active exception
The program has unexpectedly finished.
Here's the top of the stack at the time:
Code:
0 __semwait_signal 0 0x00007fff87ecdeb6
1 _pthread_cond_wait 0 0x00007fff87ed1cd1
3 QThread::wait 0 0x00000001010a419e
4 InfiniteThread::~InfiniteThread infinitethread.cpp 17 0x000000010001022c
5 EMSampleThread::~EMSampleThread emsamplethread.cpp 18 0x000000010000fbfd
6 RFViewer::~RFViewer rfviewer.cpp 50 0x0000000100008a8f
7 main main.cpp 10 0x000000010000602a
So the SIGABRT seems to be coming from QThread::wait(), which is called in ~InfiniteThread(). Code for InfiniteThread is included below. Note that InfiniteThread::centralTask() is a pure-virtual member that is re-implemented to specialize the thread for a specific task.
Like I mentioned before, InfiniteThread is based entirely on renderthread.cpp in the Mandlebrot example and it does not have this problem. Any help is much appreciated. I'm new to threading but I am pretty comfortable with Qt.
Thanks!
Seth
InfiniteThread.h:
Code:
#ifndef INFINITETHREAD_H
#define INFINITETHREAD_H
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
class InfiniteThread
: public QThread{
Q_OBJECT
public:
explicit InfiniteThread
(QObject *parent
= 0);
~InfiniteThread();
signals:
void reportProgress
(int pProg,
QString message
);
void taskDone(bool pSuccess);
protected:
void startTask();
void run();
// Override this in the child class
virtual bool centralTask() = 0;
bool restart;
bool abort;
};
#endif // INFINITETHREAD_H
InfiniteThread.cpp:
Code:
#include "infinitethread.h"
InfiniteThread
::InfiniteThread(QObject *parent
) :{
restart = false;
abort = false;
}
InfiniteThread::~InfiniteThread()
{
mutex.lock();
abort = true;
condition.wakeOne();
mutex.unlock();
wait();
}
void InfiniteThread::startTask()
{
if (!isRunning()) {
start(LowPriority);
} else {
restart = true;
condition.wakeOne();
}
}
void InfiniteThread::run()
{
forever {
// Perform central task
bool result = centralTask();
if(!restart) emit taskDone(result);
// Abort thread if requested
if(abort) return;
// Restart when new central task is given
mutex.lock();
if(!restart) condition.wait(&mutex);
restart = false;
mutex.unlock();
}
}
Re: QThread::wait() causing crash
The error says it all:
Quote:
pure virtual method called
Your problem is this line:
Code:
virtual bool centralTask() = 0;
I guess you implemented this in a subclass?
Looking at the trace, I guess the subclass gets deleted first (obviously)?
Edit: possible solution, move the run() code from your base class to the subclass.
Re: QThread::wait() causing crash
Ahhh! Yup, that makes sense. I was thoroughly confused by the error as the only pure virtual function was CentralTask() and I was re-implementing it properly. It never occurred to me that if the sub-class get's deleted then this will no longer be the case. Good eye!
Thanks!
Seth
Re: QThread::wait() causing crash
That did the trick! I worked around the deletion order by moving the code that's in the destructor into a function called stopTask(). Then, I call this from the child's destructor so the run loop will get stopped BEFORE CentralTask() becomes a pure virtual function again. Worked like a charm.
Here's the updated code:
Seth
Code:
#ifndef INFINITETHREAD_H
#define INFINITETHREAD_H
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
class InfiniteThread
: public QThread{
Q_OBJECT
public:
explicit InfiniteThread
(QObject *parent
= 0);
~InfiniteThread();
void startTask();
void stopTask();
signals:
void reportProgress
(int pProg,
QString message
);
void taskDone(bool pSuccess);
protected:
void run();
// Override this in the child class
virtual bool centralTask() = 0;
bool restart;
bool abort;
};
#endif // INFINITETHREAD_H
Code:
#include "infinitethread.h"
InfiniteThread
::InfiniteThread(QObject *parent
) :{
restart = false;
abort = false;
}
InfiniteThread::~InfiniteThread()
{
}
void InfiniteThread::stopTask()
{
mutex.lock();
abort = true;
condition.wakeOne();
mutex.unlock();
wait();
}
void InfiniteThread::startTask()
{
if (!isRunning()) {
start(LowPriority);
} else {
restart = true;
condition.wakeOne();
}
}
void InfiniteThread::run()
{
forever {
// Perform central task
bool result = centralTask();
if(!restart) emit taskDone(result);
// Abort thread if requested
if(abort) return;
// Restart when new central task is given
mutex.lock();
if(!restart) condition.wait(&mutex);
restart = false;
mutex.unlock();
}
}