4

The following scenario: I got a multiple video stream which I get from OpenCV and display in my QML GUI through a realization of a QQuickImageProvider. A signal is emitted if the images change which causes my images in the GUI to call the providers requestImage(...) function. I don't know much about the underlying realization of QImage and especially about what happens if I pass one of the images from requestImage(...) to my GUI, but the shared memory principle of QImage suggests that there might occur a problem when my OpenCV thread updates the image while it is read/passed/whatever to the GUI. Is that correct?

The approach I planned to do now is add a QMutex to the provider which is locked during image updates and requests alike and in the request function copy the requested image to a new QImage and call the "bits()" function on it, which apparently should cause a deep copy, then unlock the mutex. Does that make sense in this way? And is it necessary?

Thank you

bluewater2
  • 160
  • 7

2 Answers2

1

Read up how implicit sharing work with threading in th Qt documentation. Basically the implicit sharing is enforced by an atomic counter, but you still need to provide thread safety.

The approach I planned to do now is add a QMutex to the provider which is locked during image updates and requests alike and in the request function copy the requested image to a new QImage and call the "bits()" function on it, which apparently should cause a deep copy, then unlock the mutex. Does that make sense in this way? And is it necessary?

The doc says it make sense and that's how it should be done, except that making a deep copy of the QImage is unnecessary. Basically this should be enough for the getter.

QImage getImage() 
{
  m_mutex.lock();
  QImage img(m_image);
  m_mutex.unlock();
  return img;
}

You can probably have a classier version using QMutexLocker.

UmNyobe
  • 22,539
  • 9
  • 61
  • 90
0

QImage is one of the classes with implicit sharing (copy-on-write). Thus it is not necessary to manually copy the QImage with locking; simply invoke its copy constructor will do. The copy is shallow, but when your thread tries to update it, it will automatically do a deep copy.

Besides, why are you not passing the QImage in the signal itself?

Siyuan Ren
  • 7,573
  • 6
  • 47
  • 61
  • he is using a "pull" approach, while passing the Image will be "push". – UmNyobe Aug 27 '14 at 07:24
  • @UmNyobe: But the main thread only "pulls" when noticed by a signal, instead of "pull"ing the image on its own schedule. It is unneeded additional complexity. – Siyuan Ren Aug 27 '14 at 07:31
  • Each has its own benefit. When you start having a lot of data to give update about, "pull" is is better. `emit xAvailable();`, `emit yAvailable();` `emit zAvailable();` – UmNyobe Aug 27 '14 at 07:38
  • "Thus it is not necessary to manually copy the QImage with locking" The QT documentation suggests otherwise - and indeed I experienced crashes without any thread safety added to the function. – bluewater2 Sep 06 '14 at 20:51
  • @bluewater2: The documentation specifically says that implicit sharing and multithreading is compatible. The locking in your accepted answer is actually unnecessary overhead. What it means for "thread safety for shared instance is not guaranteed" is that you can not operate on pointers or reference to the same QImage in multiple threads. I don't know where you get your segmentation faults, but I have used such approaches before, and Application Verifier does not find any memory problems at all. – Siyuan Ren Sep 07 '14 at 01:52
  • @bluewater2: OK, I got it wrong. You are copying the QImage that belongs to a work thread from main thread. In that case, locking is indeed necessary and not redundant. – Siyuan Ren Sep 07 '14 at 01:56
  • @bluewater2: But if you adopt the approach Qt documentation advocates (passing the QImage in the signal) no locking is required. Using signal and slot to deal with multithreading is easier, safer than manual synchronization, and not prone to issues such as deadlock or starvation. Another problem with locking is that the area protected by a lock may run for a long time, blocking all other threads along the way. Signal and slot has no such problem as the time spent in locking the queue is bounded. – Siyuan Ren Sep 07 '14 at 01:59
  • @C.R. I indeed would have used a signal approach, however I couldn't find a way to display the passed QImage in my QML GUI without writing a new class for that purpose, which seemed like too much programming overhead compared to the benefits. – bluewater2 Sep 10 '14 at 23:19