Worker thread emits signals sometimes faster than main thread handles them. Where are they cached?
-
Hi All,
I've made a program that has two threads, a worker thread and the main thread. The worker thread emits signals 400 times per second. The main thread receives them in a slot. The main thread sometimes is blocking for about one second to compress the received data.
When I review the data, there are no samples missing. This means the signal/slot mechanism of Qt has cached the data, but I don't know where.
In this program the cached data was 1 second * 400 samples * 8 bytes, so about 3200 bytes.
Before I make more demanding programs that rely on this mechanism, I would like to know where Qt caches this data, what the limits are, and how I can see how close to the limits I am.
After some digging I found Qt uses a Qt::QueuedConnection between threads. How deep is this queue?
https://doc.qt.io/qt-5/threads-qobject.html#signals-and-slots-across-threadsCheers,
Cedric -
@cdwijs
Unless the experts say otherwise, my understanding is that there is no hard-coded, fixed limit for the number of events to be queued. Qt will allocate dynamic memory, so the maximum is "large". E.g. from a hundred years ago: https://www.qtcentre.org/threads/25406-What-s-the-size-of-Qt-event-queue?p=121683#post121683You can find some potential "debugging" informational code by Googling for
Qt::QueuedConnection size
. The stackoverflow ones have some "debugging" code if you wish to examine the queue length.You could also presumably have your thread ignore your hardware and just churn out as many signals as you wish to test, verifying none get dropped. You should presumably see the memory used increasing.
-
@cdwijs said in Worker thread emits signals sometimes faster than main thread handles them. Where are they cached?:
the signal/slot mechanism of Qt has cached the data, but I don't know where.
As you've already found, the data is stored in the event queue of the receiver thread (namely, the main thread in your case)
In this program the cached data was 1 second * 400 samples * 8 bytes, so about 3200 bytes.
A modern computer can comfortably handle a 400-sample or 3 KB queue. I'm not sure about an embedded system though.
The limits depend on your hardware.
Before I make more demanding programs that rely on this mechanism...
Keep an eye on your CPU and RAM. If your resource consumption is too high, consider using a "buffered acquisition" design instead. Data acquisition system APIs often support buffered mode -- this means the data gets transferred in chunks instead of sample-by-sample. For example, you could transfer your data in chunks of 200 samples, emitting 2 signals per second instead of 400 signals per second.
If your data source doesn't have a built-in buffer, you can implement your own in your worker thread: Keep adding your samples to a pre-allocated vector and emit a signal to transfer the vector once it is filled.
It is cheaper to emit 1 signal that contains many data points instead of emitting many signals that each contain 1 data point.
@JonB said in Worker thread emits signals sometimes faster than main thread handles them. Where are they cached?:
won't that potentially block the "hardware/signalling" thread?
Yes. If the sampling rate is fixed, then blocking the data acquisition loop could lead to missed samples or buffer overflows.
-
@JonB said in Worker thread emits signals sometimes faster than main thread handles them. Where are they cached?:
Laudable, but won't that potentially block the "hardware/signalling" thread?
Sure, but what else do you want to do if producer produces more than consumer can consume? At some point (if the queue is full) you have to pause the producer.
-
@jsulm
Point taken. But if the signal/slot would not block until "available memory full", while you suggest a semaphore mechanism which will block sooner or require the OP to implement his own queuing, then (politely from me!) perhaps you should mention that to the OP.The other thing, should I understand correctly, is that the OP is saying there will be intermittent periods when his slot-loop will be unable to service requests, but will then resume. This could mean that it is able to keep up provided there is queuing, as supplied by signal/slot, but with no queue in the semaphore case it will not. I am just wishing to draw his attention to that.