I have a Qt based library, that manages UDP communication with a device; connection (more like "connection", since it is UDP; I call connection to create the UDP socket and do the bind and first setup of the device), communication/data exchange, disconnection (close/delete UDP sockets).
I have a Qt GUI application that uses this library. Everything works like a charm.
Awfully, the library need to be used in a non-Qt application. I added to the library the creation of a QCoreApplication to start the event loop and be able to manage internal signals/slots (something like this). Things kinda work.
The problem is, I have no control on the non-Qt user app, especially on the use of threads. The user can create my object in the main thread, connect the device in another, disconnect it in a third one. This leads to errors like QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
. One example is when the user disconnects the device from a different thread, so the socket gets closed/destroyed in a thread different from its parent. To avoid this, I can send a signal, previously connected with QueuedConnection
, to the object, so the operation is performed in the object thread.
This leads to another problem; the user calls for a disconnection, but doesn't know when the disconnection will actually happen. Ideally, the disconnection call should be "synchronous", and exits when the disconnection is done. Ideally, I should wait for the disconnection from the object (called with signal) and then return. But how to do this? And how to do this without deadlocking the program? (e.g. slot won't be executed because current thread is waiting)
Any hint will be appreciated!
I have a Qt based library, that manages UDP communication with a device; connection (more like "connection", since it is UDP; I call connection to create the UDP socket and do the bind and first setup of the device), communication/data exchange, disconnection (close/delete UDP sockets).
I have a Qt GUI application that uses this library. Everything works like a charm.
Awfully, the library need to be used in a non-Qt application. I added to the library the creation of a QCoreApplication to start the event loop and be able to manage internal signals/slots (something like this). Things kinda work.
The problem is, I have no control on the non-Qt user app, especially on the use of threads. The user can create my object in the main thread, connect the device in another, disconnect it in a third one. This leads to errors like QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
. One example is when the user disconnects the device from a different thread, so the socket gets closed/destroyed in a thread different from its parent. To avoid this, I can send a signal, previously connected with QueuedConnection
, to the object, so the operation is performed in the object thread.
This leads to another problem; the user calls for a disconnection, but doesn't know when the disconnection will actually happen. Ideally, the disconnection call should be "synchronous", and exits when the disconnection is done. Ideally, I should wait for the disconnection from the object (called with signal) and then return. But how to do this? And how to do this without deadlocking the program? (e.g. slot won't be executed because current thread is waiting)
Any hint will be appreciated!
Share Improve this question asked Feb 6 at 15:14 il_mixil_mix 5719 silver badges26 bronze badges 4 |1 Answer
Reset to default 0One terribly ugly yet possible solution would be to add in a "front end" to the library: a QThread whose sole job is to serve as a proxy between the Qt-library code on one side, and the non-Qt application's threads on the other. Since all the handling would go through this single QThread, Qt's signals would work as expected, while the application's threads would use a custom front-end API of some sort to interface with the proxy-QThread.
So, for example:
To send a packet, an application-thread would call a method on the front-end API, which would place the packet into a message-queue of some sort, and then wake up the QThread (maybe via a call to
QCoreApplication::postEvent(theThread, ...)
) so it can asynchronously drain that message-queue and call the necessary Qt-library-functions later on.After receiving a packet, the QThread would need to add the packet into a separate "replies" message queue, and then somehow notify the user-application to check the replies-message-queue to receive the packet. (Exactly how that could be done depends on how the user-application is implemented, but most programming frameworks have some way to do it)
BlockingQueuedConnection
signal-connection type, but you're right that using it risks the possibility of deadlock if you aren't very careful about avoid cycles in your signalling patterns. – Jeremy Friesner Commented Feb 6 at 19:12BlockingQueuedConnection
in a non-Qt application I use as test bench, and indeed generated a deadlock (Qt itself prints an error when it occurs) – il_mix Commented 2 days ago