PDA

View Full Version : QT4 style QThread and GUI communication



Ronayn
22nd February 2013, 12:36
I am using QT4 to develop an application that has two parts: a worker thread and a GUI. The threads job is to wait for data to be placed in a shared memory buffer. When data is available (indicated through the use of a blocking semaphore), the thread reads the data from the buffer, processes it, and needs to pass that data to the GUI for display.

In QT4 the way of using the QThread class has changed. It is no longer recommended to subclass QThread (as it is an interface to the thread, and not the thread itself). Rather, examples show the creation of a class (based on QObject) that will actually run in the thread and perform the work.

Given that… How do I communicate from the GUI to the thread? Do I (can I) post events from the GUI – and if so, do I post them to the instance of the QThread, or to the class I created that does the actual work inside the thread? I want the GUI to be able to tell the thread to stop its blocking operation and terminate (so that the application can close), but I cannot come up with a way to do that. Example code would be much appreciated!

FYI: I had already created this application under QT3 using a subclassed QThread that polls the semaphore and posts an event to the GUI when data is ready. The GUI uses its customEvent() function to respond to the event, and a nonblocking message queue to communicate with the thread (inside its run function.) I’d like to do this differently, if possible, under QT4.

anda_skoa
22nd February 2013, 14:30
You can still subclass QThread and reimplement run(), especially if you don't need an event loop in the thread.

The "no longer recommended" bit comes from the observation that a lot of people had difficulties to understand that the QThread object itself belongs to the read that created it, not the thread executing its run() method. If one understands that (and does not try to put slots into the QThread subclass) then all is fine.

Anyway, if you want to use the worker object technique you simply make signal/slot connections between the worker and objects in the main thread. Since the worker gets moved into the thread, any signal/slot connection between it and main thread objects will be handled as Qt::QueuedConnections.
Basically very similar to your Qt3 custom event technique, but without needing any special code and working into both directions.

Note however, that as long as the worker object blocks on the semaphore, its event processing is halted and slot calls for signals from main thread objects will be queued until event processing resumes.

Cheers,
_

Ronayn
22nd February 2013, 17:52
You can still subclass QThread and reimplement run(), especially if you don't need an event loop in the thread.

The "no longer recommended" bit comes from the observation that a lot of people had difficulties to understand that the QThread object itself belongs to the read that created it, not the thread executing its run() method. If one understands that (and does not try to put slots into the QThread subclass) then all is fine.

Anyway, if you want to use the worker object technique you simply make signal/slot connections between the worker and objects in the main thread. Since the worker gets moved into the thread, any signal/slot connection between it and main thread objects will be handled as Qt::QueuedConnections.
Basically very similar to your Qt3 custom event technique, but without needing any special code and working into both directions.

Note however, that as long as the worker object blocks on the semaphore, its event processing is halted and slot calls for signals from main thread objects will be queued until event processing resumes.

Cheers,
_

Thanks for that speedy and helpful reply.

Do you have any suggestions about how to handle a worker object when its blocking on the semaphore? I suppose I could make it a non-blocking semaphore, and set up a timer event to check the semaphore. However, doing so would amount to polling in thread (which I thought was bad).

Essentially, I need a worker to sit and wait for data -- but I also need a way to break that wait from outside the thread, in case the user closes the application.

amleto
23rd February 2013, 00:26
change the semaphore for a signal/slot. That way the worker will know when to grab the data, and it is also open to receive other signals.

anda_skoa
23rd February 2013, 16:55
Essentially, I need a worker to sit and wait for data -- but I also need a way to break that wait from outside the thread, in case the user closes the application.

If you need a way to terminate the thread at any given time then you basically cannot do a call that blocks for an unspecified time.
QSystemSemaphore (assuming that is what you had in mind) is therefore out of the question, it relies on the other process calling release() reliably.

What you could do instead is making the notification part ("hey, new data available") asynchronous, e.g. by using QLocalSocket/QLocalServer.

You would still have a blocking section, i.e. while having locked() the QSharedMemory instance, but that should not be too long assuming the other process only keeps its end locked as long as necessary.

Cheers,
_

Ronayn
25th February 2013, 14:31
Thanks anda_skoa and amleto for your replies.

Unfortunately, I am constrained by the nature of what I am with. My application waits for data to be placed in a shared memory buffer by another application (which I have no control over). When that other application has placed data in the shared memory, it performs a semaphore operation to notify anyone "listening" that there is new data available.

I have to work with that :(

Like I mentioned, I have worked this out before using polling and message queues, but I did not like my solution and was hoping there was a more simple/elegant way to do what I need.

amleto
25th February 2013, 15:18
Many problems can be solved with enough levels of indirection. Consider adding another layer in between your semaphore app and your worker:

Attach the semaphore to another qt thread. Let that thread (can be blocked by semaphore) communicate with the worker (non blocking)

also let the gui communicate with the worker (signal/slot) to indicate cancelling.