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:

    @Foo::Foo()
    {
    connect(anotherThread, SIGNAL(aSignal()), this, SLOT(mySlot()));
    bar = new Bar();
    ...
    }

    Foo::~Foo()
    {
    delete bar;
    // Do more clean up
    // Could a slot be called at this point?
    }

    void Foo::mySlot()
    {
    bar->someFunc(); // bar may of been deleted!
    }@

    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.



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



  • 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:

    @
    Foo::Foo()
    : bar(new Bar)
    {
    connect(anotherThreadObject, SIGNAL(aSignal()), this, SLOT(mySlot()));
    ...
    }
    @

    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.



  • Signals slot connection are thread safe.

    But you must delete the object in its associated thread



  • [quote author="ixSci" date="1278952496"]There is no problem, all signals will be disconnected in QObject destructor. QObject destructor is called before yours.[/quote]

    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.



  • 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.



  • 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.



  • 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.



  • 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().



  • 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.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.