postEvent to potentially destroyed receiver in another thread
-
Hello, i am using QCoreApplication::post Event to send result of task from worker thread to an arbitrary receiver that lives in GUI thread. Receiver instance can be deleted during the execution of task. The Worker class stores receiver as QPointer and checks it before passing it to postEvent.
struct Task { ... QPointer<QObject> receiver; }; ... if (task.receiver) QCoreApplication::postEvent(task.receiver, new TaskResultEvent{result});
But if the receiver is actually deleted in GUI thread right after QPointer::operator T*() in worker thread the receiver parameter will become dangling and program will crash when trying to access receiver->d_func() inside postEvent.
Is there safe way to send events for such cases without using signal-slot connections?
Sorry for my English -
@BigOleg said in postEvent to potentially destroyed receiver in another thread:
program will crash when trying to access receiver->d_func() inside postEvent.
There is a saying that says "often, a sufficiently well-formed problem statement is indistinguishable from a solution."
You have described the problem very clearly.
There is indeed a solution that I can envision quite clearly in conceptual terms. I leave it up to you to "port" the following conceptual solution to actual nuts-and-bolts of using QPointer or other Qt features:
You need another layer of indirection. When the asynchronous event is "unpacked" (currently happening inside the application event loop when the posted-event is actually handled), at that later asynchronous point is when you need to check
if (task.receiver)
to guard against a crash.So you need to "post" a more involved bit of work. You need to queue up something more like a lambda, such that when the application event loop pulls the work off the queue in the GUI thread, the
if (task.receiver)
happens at THAT point. It needs to happen when the work is dequeued, not when it is enqueued. (Although you may wish to check for null in both places.) -
The purpose of the worker thread is to manage resources (for example, a connection to a database) whose opening/closing operations are relatively expensive. And widgets (with their lifetime) use this connection to query their data by sending tasks (e.g. query sets) through lightweight task instances.
-
@BigOleg said in postEvent to potentially destroyed receiver in another thread:
program will crash when trying to access receiver->d_func() inside postEvent.
There is a saying that says "often, a sufficiently well-formed problem statement is indistinguishable from a solution."
You have described the problem very clearly.
There is indeed a solution that I can envision quite clearly in conceptual terms. I leave it up to you to "port" the following conceptual solution to actual nuts-and-bolts of using QPointer or other Qt features:
You need another layer of indirection. When the asynchronous event is "unpacked" (currently happening inside the application event loop when the posted-event is actually handled), at that later asynchronous point is when you need to check
if (task.receiver)
to guard against a crash.So you need to "post" a more involved bit of work. You need to queue up something more like a lambda, such that when the application event loop pulls the work off the queue in the GUI thread, the
if (task.receiver)
happens at THAT point. It needs to happen when the work is dequeued, not when it is enqueued. (Although you may wish to check for null in both places.) -
Hi,
Following @KH-219Design suggestion, you should have a task manager rather than relying on the task object itself to do all the job.