Kadir Erdem Demir
Kadir Erdem Demir

Reputation: 3605

Qt Object deleted but signal is not disconnected

In this topic it told when a qobject deleted its active connections will be deleted. I have a case like below:

Work* work = new Work();//->Work derived from QObject 
Worker* worker  = new Worker(work);//->Worker derived from QThread and has the ownership of work

connect(work, SIGNAL(percentageComplete(int)), progressDialog, SLOT(setValue(int)));
connect(worker, SIGNAL(finished()),  worker, SLOT(deleteLater()));

progressDialog->show();
worker->start();

In worker's destructor I have :

Worker::~Worker(void){
    if(work != nullptr){
        work->deleteLater();
    }
}

I am %100 sure that work is deleted. I can see it with a breakpoint. I can even see QObjects desctructor call.

But some how deleted work object still receiving signal "percentage complete". And because it is deleted ,causing a crush.

I want to ask why signals are not disconnected even object is deleted?

A second question in Worker's destructor work->deleteLater(); or delete work; is correct?

Upvotes: 0

Views: 3295

Answers (4)

This happens because there are two threads attempting to use Work at the same time, with no apparent synchronization, with predictably bad results.

You have to marshal the ownership of and access to Work between the main thread and the worker thread, so that the two threads can't access it at the same time in an unsafe manner.

The destructor of Worker is not executed in the Worker thread! Furthermore, I don't see any code that prevents that destructor from running while the Worker thread is still active. Note that a QThread is not a thread, but a thread handle. It's a deceptive name.

Alas, your question can't be answered without seeing a complete example that reproduces the issue.

Upvotes: 0

ramtheconqueror
ramtheconqueror

Reputation: 1964

Until unless you have some custom code, just use QThreaddirectly.

Work* work = new Work(); // no parent
QThread* thread = new QThread();

work->moveToThread(worker);

connect(thread, SIGNAL(started()), work, SLOT(doSomeWork())); // add this function doSomething() in Work class which on completion should emit finished() signal
connect(work, SIGNAL(finished()), thread, SLOT(quit())); // quit the thread
connect(work, SIGNAL(finished()), work, SLOT(deleteLater())); // delete work after job done
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); // delete thread

// if you are using c++11, do this to see Work and Thread deletion
connect(work, &Work::destroyed, [](){ qDebug() << "Work object deleted"; });
connect(thread, &QThread::destroyed, [](){ qDebug() << "Thread deleted"; });

// start the thread now
thread->start();

See here for more info on QThread usage

Upvotes: 0

Szymson
Szymson

Reputation: 1132

Why dont you use disconnect() for disconnect all connected slots/signals ? You can call this function in destructor.Here you have solution from similar topic

Upvotes: 3

Martin Saleteg
Martin Saleteg

Reputation: 1

My guess is that the work object is moved to the worker thread, and that the signal emitted will end up on the event loop, which can be delivered a bit later. Probably you have killed progressDialog at that point.

Upvotes: 0

Related Questions