Deleting QObject during signal/slot processing - c++

I know that deleting a QObject from a slot processing could crash the app because it could have other queued events.
So, instead of use "delete obj" i will use obj->deleteLater(). As far as I know the obj waits to process all queued events and then "delete obj".
QObject::~QObject ()
All signals to and from the object are automatically disconnected, and any pending posted events for the object are removed from the event queue. However, it is often safer to use deleteLater() rather than deleting a QObject subclass directly.
But, what's about other signal/slot processes? I mean, if you have connected signals/slot from objects which live in different threads as Qt::QueuedConnection or Qt::BlockingQueuedConnection. Are they dequeued to be processed?
Thanks in advance.

deleteLater will remove object from thread which object belongs to. Qt::QueuedConnection and Qt::BlockingQueuedConnection (also Qt::AutoConnection) are work in this way that slot is invoked from event loop of thread which object with slot belongs to.
So if you add to this quote you posted this means that any pending Qt::*QueuedConnection will be automatically dismissed when object gets destroyed. This means that you are safe when using those connections and deleteLater. Problem may appear when you will use Qt::DirectConnection with different thread, or when you try to destroy object directly (delete pointer;) from wrong thread.

As per Qt Documents
The object will be deleted when control returns to the event loop. If
the event loop is not running when this function is called (e.g.
deleteLater() is called on an object before QCoreApplication::exec()),
the object will be deleted once the event loop is started. If
deleteLater() is called after the main event loop has stopped, the
object will not be deleted. Since Qt 4.8, if deleteLater() is called
on an object that lives in a thread with no running event loop, the
object will be destroyed when the thread finishes.
Note that entering and leaving a new event loop (e.g., by opening a
modal dialog) will not perform the deferred deletion; for the object
to be deleted, the control must return to the event loop from which
deleteLater() was called.
Note: It is safe to call this function more than once; when the first
deferred deletion event is delivered, any pending events for the
object are removed from the event queue.
In Qt::QueuedConnection type deleteLater() will wait to finish thread.but In Qt::DirectConnection when anyone delete object directly, it may crash the application.
In that case you need to check thread is running or not before deleting.

Related

Using deleteLater() for an object with a cyclic timer

I create an object of a class that has a QTimer that runs cyclically.
The client of the program can request the removal of the task that the object is doing, which will delete the object.
When using object->deleteLate(); the object is never deleted, but with delete object; it works.
Is this due to the timer field in the object running cyclically?
The documentation for ~QObject says:
All signals to and from the object are automatically disconnected, and any pending posted events for the object are removed from the event queue. However, it is often safer to use deleteLater() rather than deleting a QObject subclass directly.
Emphasis is mine. In a note later in the same document
Warning: Deleting a QObject while pending events are waiting to be delivered can cause a crash. You must not delete the QObject directly if it exists in a different thread than the one currently executing. Use deleteLater() instead, which will cause the event loop to delete the object after all pending events have been delivered to it.
Emphasis is mine. This means your cyclic timer, upon re-adding itself, would cause the object to always have a pending event.
If you want to use deleteLater(), then your cyclic timer should detect whether a deleteLater() is in progress, and then cancel itself if so. Then, your deletion will occur after any other pending event has been cleared.

Is it safe to call deleteLater right after emitting a signal with the object?

I believe the following code is safe, but I have not been able to confirm it:
void someMethod(Process *process) {
emit signalWithProcess(process);
process->deleteLater();
}
I'm not sure if process still exists when the signals are called and auto or queued connections are used.
For direct connections, the code above is correct because the slots are called synchronously. AFAIK, for slots on the same thread as the object, it is also correct because deleteLater() posts a new event to the object's event loop. However, the signal events are posted earlier so they run earlier.
However, for queued connections on different threads I do not understand how it works and whether the code above is safe. My gut-feeling says yes, but I have not been able to verify it.
For example, the process object above belongs to thread A and there's a queued connection to another object on thread B. When someMethod() runs, it adds the queued signals to thread B's event loop and adds the deleteLater event to thread A's event loop.
Unless there is some way to block thread A from deleting the object while the slot is run in thread B, this seems not to be safe. Unfortunately, I have not found anything related to that in the source code or the documentation.
Similar question (but without deleteLater): Is it safe to emit signal passing QObject pointer as parameter right before the passed object is going to be destroyed?

If Qt signals aren't handled because the receiving object's thread has ended, will the arguments be deleted?

Consider that object A is bound to thread T1 and a signal sig1 with an argument of QList < QVariantMap > is fired from thread T2.
The signal is queued on A's event loop, but before handling, A's thread (T1) is quit. The QList< QVariantMap > argument of sig1 is obviously allocated on the stack, I'm guessing that it should clean up itself.
But when? Perhaps when the QThread object itself is destroyed? Does anyone have specific knowledge in this area? In my system, this thread will not simply run once and end at shutdown. It may potentially be started, run for hours, and then quit and be started again later on.
The argument will not be deleted if the thread has been terminated in a correct way like
QThread t;
t.exit();
t.wait();
Now you assert that
The QList< QVariantMap > argument of sig1 is obviously allocated on
the stack
It is not that obvious. Because the receiving thread need to use the data in a deferred execution, emit(myVariantList) will eventually lead to a copy of myVariantList. You don't know where the copy is going to be allocated.
Now to allow posting events with eventual data , ie the classic
Mywidget m;
m.show(); <-- this post at least one event
app.exec();
Those posted events need to be saved just in case of an eventual execution of the event loop. I believe that if the object holding the event loop is not destroyed or the user doesn't explicitly ask for events to be removed, they stay for the lifetime of the QObject.

QObject::deleteLater across a QThread

I'm looking for a solution to schedule the deletion of an object across threads. The docs about how deleteLater behave are not entirely clear. Can I call this function in a thread which is not the object's owner?
For example, Object X is owned by Thread A, and in Thread B I would like to have Object X deleted. As the object may be inside event processing at the moment (in Thread A) I can't safely delete it until it gets back to the message loop. If I call deleteLater from Thread B however the docs seem to indicate it will delete as soon as Thread B gets back to the message loop.
Currently I take the approach of having a signal emitted in Thread A which is attached to a slot which calls deleteLater. I'm wondering if there is perhaps an easier way to do this -- if indeed I can just call deleteLater from any thread.
Looking at the Qt 4 code and Qt 5 code, deleteLater() just invokes QCoreApplication::postEvent() which is explicitly declared thread-safe. So, it should be fine to just call it directly. As the event queue is processed in the object's owner thread, deletion will happen in thread A.
Only Qt 5 QObject documentation explicitly lists deleteLater() as thread safe. If you want to completely rely on documented behaviour in Qt 4, use postEvent().
While deleteLater() is not safe itself, you can invoke it in object's threadA with meta call:
metaObject()->invokeMethod(object, "deleteLater", Qt::QueuedConnection);
Then, it will be safe.
deleteLater() only means that the object will be deleted after all signal/slots int the current event loop (i.e. ThreadB) have been treated.
So, if no other slots need ObjectX in ThreadB, it is equivalent to a plain delete.
Whether you can delete the object or not and how it will be handled in ThreadA is up to your app logic.
If ObjectX is the main object of the thread, sending the quit() signal to ThreadA is the way to go.

QMetaObject::invokeMethod returns true, but method is never called

I'm trying to run a method on the GUI thread using QMetaObject::invokeMethod, which returns true. But, if I use Qt::QueuedConnection my method never gets called (even if invokeMethod returns true).
This is what I'm using:
QMetaObject::invokeMethod(this, "draw_widgets", Qt::QueuedConnection)
I don't get any error messages or anything...
If I use Qt::AutoConnection or Qt::DirectConnection the method does get called, but from the same thread of course. Not from the GUI thread, which is what I need.
draw_widgets is a public slot of type void draw_widgets()
and my class inherits QObject and uses the Q_OBJECT macro as well.
I would appreciate any help on this, or on how to check why the method is not being called.
Thanks.
The "true" is telling you the message was successfully queued. That doesn't mean the queued message was ever processed...
Let us say your program has 10 threads (Thread1-Thread10). You queue a message from Thread7. Which thread will it be queued to? And when will items on this queue be processed?
The answer is that every QObject has something called Thread Affinity, and this is the thread where a queued slot will be run. The default affinity is to the thread where the object was created (but you can change it with QObject::moveToThread().)
If you want to queue something to the GUI thread, then the object specified by your this pointer should have the GUI thread's affinity. You can check this with the QObject::thread() method.
But in any case, no matter what thread you queue to... you must have some kind of message pump running on that thread. Look at for instance QThread::exec(). If your thread affinity is to the GUI then presumably this is already the case because you are running the app's exec.
(As a sidenote, direct calls to QMetaObject::invokeMethod are usually unnecessary. You can create a signal and tie it to a slot, then emit the signal in lieu of the invoke.)