Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<h2>Unsafe Manners</h2> <p>Calling any generic QWidget method directly from a different thread is unsafe, because the behavior of Qt and underlying C++-generated code in undefined. It may launch a nuclear first strike. You have been warned. Thus you cannot call <code>QWidget::update()</code>, <code>QLabel::setText(...)</code>, or any other such methods from a separate thread unless you use safe interthread communication offered by Qt.</p> <h3>Wrong</h3> <pre><code>// in a separate thread widget-&gt;update(); widget-&gt;setText("foo"); </code></pre> <h3>Right</h3> <pre><code>// in a separate thread // using QMetaObject::invokeMethod(widget, "update") is unoptimal QCoreApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority); QMetaObject::invokeMethod(widget, "setText", Q_ARG(QString, "foo")); </code></pre> <h2>On Interthread Communication</h2> <p>A trivial way of communicating with a thread that contains some QObjects involves posting events to it via the static <code>QCoreApplication::postEvent()</code> method. The GUI thread is a common example of a thread where a whole bunch of QObjects reside. Using <code>postEvent()</code> is always thread safe. This method does not care <em>at all</em> which thread it's called from.</p> <p>There are various static methods scattered across Qt that internally use <code>postEvent()</code>. Their key signature is that they, too, will be static! The <code>QMetaObject::invokeMethod(...)</code> family is such an example.</p> <p>When you connect signals to slots in QObjects that live in different threads, a queued connection is used. With such a connection, every time the signal is emitted, a <code>QMetaCallEvent</code> is constructed and posted to the target QObject, using -- you guessed it right -- <code>QCoreApplication::postEvent()</code>.</p> <p>So, connecting a signal from a QObject in some non-GUI thread to the <code>QWidget::update()</code> slot is safe, because internally such a connection uses <code>postEvent()</code> to propagate the signals across the thread barrier. The event loop in the GUI thread will pick it up and execute an actual call to the <code>QWidget::update()</code> on your label. Fully thread safe.</p> <h2>Optimizations</h2> <p>The only problem with using a signal-slot connection or method invocation across threads is that Qt is unaware that your updates should be compressed. Every time you emit your signal connected to <code>QWidget::update()</code> in a separate thread, or every time you call <code>invokeMethod</code>, there is an event posted to an event queue.</p> <p>The idiomatic, if undocumented, way of doing an across-threads update is:</p> <pre><code>QApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority); </code></pre> <p>The UpdateRequest events get compressed by Qt. At any time, there can be only one such event in the event queue for a particular widget. So, once you post first such an event, the subsequent ones will be ignored until the widget actually consumes the event and repaints (updates) itself.</p> <p>So, how about our various widget-setting calls, such as, for example <code>QLabel::setText()</code>? Surely it would be cool if we could somehow compress those as well? Yes, it is certainly possible, but we have to limit ourselves to public Qt interfaces. Qt doesn't offer anything obvious here.</p> <p>The key is to remove any pending <code>QMetaCallEvent</code> from the widget's event queue before posting another one. This is safe only if we're sure that the queued signal-slot connections to given widget are only coming from us. This is usually a safe assumption, because everything in the GUI thread uses automatic connections, and those will default to directly invoking the slots without posting events to the event queue of the GUI thread.</p> <p>Here's how:</p> <pre><code>QCoreApplication::removePostedEvents(label, QEvent::MetaCall); QMetaObject::invokeMethod(label, "setText", Q_ARG(QString, "foo")); </code></pre> <p>Note that for performance reasons we use a normalized representation of the slot: no extra spaces, and all <code>const Type &amp;</code> are converted to simply <code>Type</code>.</p> <p>Note: In my own projects, I sometimes use private Qt event compression APIs, but I won't advocate doing that here.</p> <h2>Postscriptum</h2> <p>The C code should not be calling <code>QObject::connect</code>, I think it's a sign of bad design. If you want to communicate from the C code to the Qt code, use the static <code>QCoreApplication::postEvent(...)</code> (suitably wrapped/exposed to C, of course). To communicate the other way, you can hand-code an event queue in your thread(s). At a minimum, the "event queue" will be just a fixed structure, but the point is to use a mutex to protect access to it.</p> <p>Another sign of bad design is that code external to a GUI class depends on the individual UI items within that class itself. You should provide a set of signals and slots on the overall UI class (say your <code>MainWindow</code>), and forward those to relevant UI elements internally. You can <code>connect()</code> signals to signals, but not slots to slots -- you'll have to code the forwarding slots manually.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload