There are two classes: Widget
and Worker
. Here is a schematic code.
class Widget
{
Worker *m_worker;
QTextEdit *m_edit;
public:
Widget():m_edit(new QTextEdit){}
~Widget()
{
m_worker->ShouldStop = true;
delete *m_worker;
}
void doWork()
{
m_worker = new Worker;
if (!worker->doWork())
m_edit->setText("failed");
}
}
class Worker
{
Worker() : ShouldStop(false){}
public:
bool ShouldStop;
bool doWork()
{
while(true && !ShouldStop)
{
QThread::sleep(1);
QApplication::processEvents();
}
//consider the work undone if a stop was forced
if (ShouldStop)
return false;
}
}
After a call to doWork()
of the Widget
the execution loops in the method doWork()
of the Worker
. A widget is then closed and its destructor is called during one of the calls to processEvents()
. Then the execution then returns to the doWork()
of the Worker
.
It now checks ShouldStop
and returns to the doWork()
of the Widget
and tries to add something to the m_edit
. However the Widget
object is already dead.
Questions:
Ideally, worker threads should just return data via the signals and slots mechanism, not directly accessing the original object. Actually creating a thread and avoiding the call to QApplication::processEvents()
is the first way to avoid the problem.
Additionally, you should consider using a design like this when you want to start a worker in a new thread. Rather than subclassing QThread, you can just create a generic QThread and assign a QObject to it, like so:
Worker *worker = new Worker;
QThread *workerThread = new QThread(this);
connect(workerThread, &QThread::started, worker, &Worker::doWork);
connect(workerThread, &QThread::finished, worker, &Worker::deleteLater);
worker->moveToThread(workerThread);
// Starts an event loop, and emits workerThread->started()
workerThread->start();
Consider restructuring your code around this pattern if you're using Qt 5.