July 12, 2010

robcaldecott robcaldecott
Lab Rat
1 posts

Cross-thread signals, disconnect and destructors

 

If I have an object which has connected to signals that will be emitted from another thread is there any danger that the slots can be called on my object whilst it is being destructed? For example:

  1. Foo::Foo()
  2. {
  3.   connect(anotherThread, SIGNAL(aSignal()), this, SLOT(mySlot()));
  4.   bar = new Bar();
  5.   ...
  6. }
  7.  
  8. Foo::~Foo()
  9. {
  10.   delete bar;
  11.   // Do more clean up
  12.   // Could a slot be called at this point?
  13. }
  14.  
  15. void Foo::mySlot()
  16. {
  17.   bar->someFunc(); // bar may of been deleted!
  18. }

Now, I can easily add a call to disconnect() as the first thing in my destructor but I wanted to check if this was a potential problem or not.

9 replies

July 12, 2010

ixSci ixSci
Lab Rat
206 posts

There is no problem, all signals will be disconnected in QObject destructor. QObject destructor is called before yours.

July 13, 2010

Bobs Bobs
Lab Rat
34 posts

One small correction: it will be more accurate to create a Bar() object before connecting a slot that uses it. Something like that would be just fine:

  1. Foo::Foo()
  2.   : bar(new Bar)
  3. {
  4.   connect(anotherThreadObject, SIGNAL(aSignal()), this, SLOT(mySlot()));
  5.   ...
  6. }

There is also some small detail about the connection. If you want the signal to be invoked asyncroniously the anotherThread object must me already moved to another thread (see QObject::moveToThread()) when you call connect(). In this case mySlot() will be invoked asyncroniously.

 Signature 

Nokia Certified Qt Specialist.

July 16, 2010

Olivier Goffart Olivier Goffart
Lab Rat
21 posts

Signals slot connection are thread safe.

But you must delete the object in its associated thread

July 16, 2010

harryF harryF
Lab Rat
33 posts
ixSci wrote:
There is no problem, all signals will be disconnected in QObject destructor. QObject destructor is called before yours.

Destructors happen from most special class to parent class, so if your class inherits from QObject, the QObject destructor is called after your destructor. However, unless you have a function that spins the event loop during destruction, you should be safe to assume that while the object is being destructed, no slots are called.

 Signature 

// happy hacking

July 17, 2010

Olivier Goffart Olivier Goffart
Lab Rat
21 posts

slot are called using the virtual function qt_metacall.

Since the pointer to the virtual table is changed in each individual destructor, there is no way a slot can be called if the destructor has been ran.

July 17, 2010

Zlatomir Zlatomir
Hobby Entomologist
361 posts

And not even between the run of destructors in a class hierarchy.

The destructors are by default virtual if a class in hierarchy has virtual destructor (in our case QObject class even if you derive from another class derived from QObject that doesn’t have virtual destructor) so they are called one after another, and disconnect their signals/slots connections.

But why do you ask this question?
I think it is your job as programmer to make sure that if you connect two objects they will be “alive” in the same time.

December 5, 2010

mbroadst mbroadst
Lab Rat
8 posts

Make sure that when you’re deleting the parent QObject that you call “deleteLater()” on it, instead of just deleting it manually. Also, in order a very easy way to ensure that you don’t act on that object after it has been deleted (I’m speaking of foo in this case) is to wrap it with a smart pointer and check if its null before accessing it.

December 5, 2010

Lenz Moser Lenz Moser
Lab Rat
1 posts

I simply put a call to this->disconnect() in the destructor at first.

I’ve seen several core dumps caused by signals to already deleted objects, but not since I use disconnect().

December 6, 2010

mbroadst mbroadst
Lab Rat
8 posts

Lenz: Connections are automatically disconnected in the QObject destructor. By calling deleteLater() you let event loop clean up any signals that haven’t been processed yet before the object is deleted, you can generally avoid issues like you’re talking about by letting Qt delete QObject subclasses for you.

 
  ‹‹ QMake and make with parallel jobs [bug?]      Porting QListView to QTreeWidget ››

You must log in to post a reply. Not a member yet? Register here!