Doc: Move threading overviews from qtbase.git to qtdoc.git
- This topic is relevant to multiple modules, as illustrated by the "Thread-Support in Qt Modules" page. Multithreading can be done in both C++ and QML. - Moving also fixes links to QML-related pages. - Snippets are copied, not moved. QThreadStorage docs need them. - QDoc: "DEPENDS += qtdoc" added to keep the "\reentrant" command working. It creates a link to the "reentrant" keyword. Change-Id: I2cdf6139e62d66911561c30fcca7aab160a694b1 Reviewed-by: Jerome Pasion <jerome.pasion@digia.com>
This commit is contained in:
parent
8647bac9cf
commit
706eeadf3a
Binary file not shown.
Before Width: | Height: | Size: 64 KiB |
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
@ -1,244 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
|
||||||
** Contact: http://www.qt-project.org/legal
|
|
||||||
**
|
|
||||||
** This file is part of the documentation of the Qt Toolkit.
|
|
||||||
**
|
|
||||||
** $QT_BEGIN_LICENSE:FDL$
|
|
||||||
** Commercial License Usage
|
|
||||||
** Licensees holding valid commercial Qt licenses may use this file in
|
|
||||||
** accordance with the commercial license agreement provided with the
|
|
||||||
** Software or, alternatively, in accordance with the terms contained in
|
|
||||||
** a written agreement between you and Digia. For licensing terms and
|
|
||||||
** conditions see http://qt.digia.com/licensing. For further information
|
|
||||||
** use the contact form at http://qt.digia.com/contact-us.
|
|
||||||
**
|
|
||||||
** GNU Free Documentation License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU Free
|
|
||||||
** Documentation License version 1.3 as published by the Free Software
|
|
||||||
** Foundation and appearing in the file included in the packaging of
|
|
||||||
** this file. Please review the following information to ensure
|
|
||||||
** the GNU Free Documentation License version 1.3 requirements
|
|
||||||
** will be met: http://www.gnu.org/copyleft/fdl.html.
|
|
||||||
** $QT_END_LICENSE$
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\page thread-basics.html
|
|
||||||
\ingroup tutorials
|
|
||||||
\startpage {index.html}{Qt Reference Documentation}
|
|
||||||
|
|
||||||
\title Threading Basics
|
|
||||||
\brief An introduction to threads
|
|
||||||
|
|
||||||
\section1 What Are Threads?
|
|
||||||
|
|
||||||
Threads are about doing things in parallel, just like processes. So how do
|
|
||||||
threads differ from processes? While you are making calculations on a
|
|
||||||
spreadsheet, there may also be a media player running on the same desktop
|
|
||||||
playing your favorite song. Here is an example of two processes working in
|
|
||||||
parallel: one running the spreadsheet program; one running a media player.
|
|
||||||
Multitasking is a well known term for this. A closer look at the media
|
|
||||||
player reveals that there are again things going on in parallel within one
|
|
||||||
single process. While the media player is sending music to the audio driver,
|
|
||||||
the user interface with all its bells and whistles is being constantly
|
|
||||||
updated. This is what threads are for -- concurrency within one single
|
|
||||||
process.
|
|
||||||
|
|
||||||
So how is concurrency implemented? Parallel work on single core CPUs is an
|
|
||||||
illusion which is somewhat similar to the illusion of moving images in
|
|
||||||
cinema.
|
|
||||||
For processes, the illusion is produced by interrupting the processor's
|
|
||||||
work on one process after a very short time. Then the processor moves on to
|
|
||||||
the next process. In order to switch between processes, the current program
|
|
||||||
counter is saved and the next processor's program counter is loaded. This
|
|
||||||
is not sufficient because the same needs to be done with registers and
|
|
||||||
certain architecture and OS specific data.
|
|
||||||
|
|
||||||
Just as one CPU can power two or more processes, it is also possible to let
|
|
||||||
the CPU run on two different code segments of one single process. When a
|
|
||||||
process starts, it always executes one code segment and therefore the
|
|
||||||
process is said to have one thread. However, the program may decide to
|
|
||||||
start a second thread. Then, two different code sequences are processed
|
|
||||||
simultaneously inside one process. Concurrency is achieved on single core
|
|
||||||
CPUs by repeatedly saving program counters and registers then loading the
|
|
||||||
next thread's program counters and registers. No cooperation from the
|
|
||||||
program is required to cycle between the active threads. A thread may be in
|
|
||||||
any state when the switch to the next thread occurs.
|
|
||||||
|
|
||||||
The current trend in CPU design is to have several cores. A typical
|
|
||||||
single-threaded application can make use of only one core. However, a
|
|
||||||
program with multiple threads can be assigned to multiple cores, making
|
|
||||||
things happen in a truly concurrent way. As a result, distributing work
|
|
||||||
to more than one thread can make a program run much faster on multicore
|
|
||||||
CPUs because additional cores can be used.
|
|
||||||
|
|
||||||
\section2 GUI Thread and Worker Thread
|
|
||||||
|
|
||||||
As mentioned, each program has one thread when it is started. This thread
|
|
||||||
is called the "main thread" (also known as the "GUI thread" in Qt
|
|
||||||
applications). The Qt GUI must run in this thread. All widgets and several
|
|
||||||
related classes, for example QPixmap, don't work in secondary threads.
|
|
||||||
A secondary thread is commonly referred to as a "worker thread" because it
|
|
||||||
is used to offload processing work from the main thread.
|
|
||||||
|
|
||||||
\section2 Simultaneous Access to Data
|
|
||||||
|
|
||||||
Each thread has its own stack, which means each thread has its own call
|
|
||||||
history and local variables. Unlike processes, threads share the same
|
|
||||||
address space. The following diagram shows how the building blocks of
|
|
||||||
threads are located in memory. Program counter and registers of inactive
|
|
||||||
threads are typically kept in kernel space. There is a shared copy of the
|
|
||||||
code and a separate stack for each thread.
|
|
||||||
|
|
||||||
\image threadvisual-example.png "Thread visualization"
|
|
||||||
|
|
||||||
If two threads have a pointer to the same object, it is possible that both
|
|
||||||
threads will access that object at the same time and this can potentially
|
|
||||||
destroy the object's integrity. It's easy to imagine the many things that
|
|
||||||
can go wrong when two methods of the same object are executed
|
|
||||||
simultaneously.
|
|
||||||
|
|
||||||
Sometimes it is necessary to access one object from different threads;
|
|
||||||
for example, when objects living in different threads need to communicate.
|
|
||||||
Since threads use the same address space, it is easier and faster for
|
|
||||||
threads to exchange data than it is for processes. Data does not have to be
|
|
||||||
serialized and copied. Passing pointers is possible, but there must be a
|
|
||||||
strict coordination of what thread touches which object. Simultaneous
|
|
||||||
execution of operations on one object must be prevented. There are several
|
|
||||||
ways of achieving this and some of them are described below.
|
|
||||||
|
|
||||||
So what can be done safely? All objects created in a thread can be used
|
|
||||||
safely within that thread provided that other threads don't have references
|
|
||||||
to them and objects don't have implicit coupling with other threads. Such
|
|
||||||
implicit coupling may happen when data is shared between instances as with
|
|
||||||
static members, singletons or global data. Familiarize yourself with the
|
|
||||||
concept of \l{Reentrancy and Thread-Safety}{thread safe and reentrant}
|
|
||||||
classes and functions.
|
|
||||||
|
|
||||||
\section1 Using Threads
|
|
||||||
|
|
||||||
There are basically two use cases for threads:
|
|
||||||
|
|
||||||
\list
|
|
||||||
\li Make processing faster by making use of multicore processors.
|
|
||||||
\li Keep the GUI thread or other time critical threads responsive by
|
|
||||||
offloading long lasting processing or blocking calls to other threads.
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
\section2 When to Use Alternatives to Threads
|
|
||||||
|
|
||||||
Developers need to be very careful with threads. It is easy to start other
|
|
||||||
threads, but very hard to ensure that all shared data remains consistent.
|
|
||||||
Problems are often hard to find because they may only show up once in a
|
|
||||||
while or only on specific hardware configurations. Before creating threads
|
|
||||||
to solve certain problems, possible alternatives should be considered.
|
|
||||||
|
|
||||||
\table
|
|
||||||
\header
|
|
||||||
\li Alternative
|
|
||||||
\li Comment
|
|
||||||
\row
|
|
||||||
\li QEventLoop::processEvents()
|
|
||||||
\li Calling QEventLoop::processEvents() repeatedly during a
|
|
||||||
time-consuming calculation prevents GUI blocking. However, this
|
|
||||||
solution doesn't scale well because the call to processEvents() may
|
|
||||||
occur too often, or not often enough, depending on hardware.
|
|
||||||
\row
|
|
||||||
\li QTimer
|
|
||||||
\li Background processing can sometimes be done conveniently using a
|
|
||||||
timer to schedule execution of a slot at some point in the future.
|
|
||||||
A timer with an interval of 0 will time out as soon as there are no
|
|
||||||
more events to process.
|
|
||||||
\row
|
|
||||||
\li QSocketNotifier QNetworkAccessManager QIODevice::readyRead()
|
|
||||||
\li This is an alternative to having one or multiple threads, each with
|
|
||||||
a blocking read on a slow network connection. As long as the
|
|
||||||
calculation in response to a chunk of network data can be executed
|
|
||||||
quickly, this reactive design is better than synchronous waiting in
|
|
||||||
threads. Reactive design is less error prone and energy efficient
|
|
||||||
than threading. In many cases there are also performance benefits.
|
|
||||||
\endtable
|
|
||||||
|
|
||||||
In general, it is recommended to only use safe and tested paths and to
|
|
||||||
avoid introducing ad-hoc threading concepts. The QtConcurrent module provides an easy
|
|
||||||
interface for distributing work to all of the processor's cores. The
|
|
||||||
threading code is completely hidden in the QtConcurrent framework, so you
|
|
||||||
don't have to take care of the details. However, QtConcurrent can't be used
|
|
||||||
when communication with the running thread is needed, and it shouldn't be
|
|
||||||
used to handle blocking operations.
|
|
||||||
|
|
||||||
\section2 Which Qt Thread Technology Should You Use?
|
|
||||||
|
|
||||||
See the \l{Multithreading Technologies in Qt} page for an introduction to the
|
|
||||||
different approaches to multithreading to Qt, and for guidelines on how to
|
|
||||||
choose among them.
|
|
||||||
|
|
||||||
|
|
||||||
\section1 Qt Thread Basics
|
|
||||||
|
|
||||||
The following sections describe how QObjects interact with threads, how
|
|
||||||
programs can safely access data from multiple threads, and how asynchronous
|
|
||||||
execution produces results without blocking a thread.
|
|
||||||
|
|
||||||
\section2 QObject and Threads
|
|
||||||
|
|
||||||
As mentioned above, developers must always be careful when calling objects'
|
|
||||||
methods from other threads. \l{QObject#Thread Affinity}{Thread affinity}
|
|
||||||
does not change this situation.
|
|
||||||
Qt documentation marks several methods as thread-safe.
|
|
||||||
\l{QCoreApplication::}{postEvent()} is a noteworthy example. A thread-safe
|
|
||||||
method may be called from different threads simultaneously.
|
|
||||||
|
|
||||||
In cases where there is usually no concurrent access to methods, calling
|
|
||||||
non-thread-safe methods of objects in other threads may work thousands
|
|
||||||
of times before a concurrent access occurs, causing unexpected behavior.
|
|
||||||
Writing test code does not entirely ensure thread correctness, but it is
|
|
||||||
still important.
|
|
||||||
On Linux, Valgrind and Helgrind can help detect threading errors.
|
|
||||||
|
|
||||||
\section2 Protecting the Integrity of Data
|
|
||||||
|
|
||||||
When writing a multithread application, extra care must be taken to avoid
|
|
||||||
data corruption. See \l{Synchronizing Threads} for a discussion on how to
|
|
||||||
use threads safely.
|
|
||||||
|
|
||||||
\section2 Dealing with Asynchronous Execution
|
|
||||||
|
|
||||||
One way to obtain a worker thread's result is by waiting for the thread
|
|
||||||
to terminate. In many cases, however, a blocking wait isn't acceptable. The
|
|
||||||
alternative to a blocking wait are asynchronous result deliveries with
|
|
||||||
either posted events or queued signals and slots. This generates a certain
|
|
||||||
overhead because an operation's result does not appear on the next source
|
|
||||||
line, but in a slot located somewhere else in the source file. Qt
|
|
||||||
developers are used to working with this kind of asynchronous behavior
|
|
||||||
because it is much similar to the kind of event-driven programming used in
|
|
||||||
GUI applications.
|
|
||||||
|
|
||||||
\section1 Examples
|
|
||||||
|
|
||||||
Qt comes with several examples for using threads. See the class references
|
|
||||||
for QThread and QThreadPool for simple examples. See the \l{Threading and
|
|
||||||
Concurrent Programming Examples} page for more advanced ones.
|
|
||||||
|
|
||||||
\section1 Digging Deeper
|
|
||||||
|
|
||||||
Threading is a very complicated subject. Qt offers more classes for
|
|
||||||
threading than we have presented in this tutorial. The following materials
|
|
||||||
can help you go into the subject in more depth:
|
|
||||||
|
|
||||||
\list
|
|
||||||
\li Good video tutorials about threads with Qt can be found in the material
|
|
||||||
from the \l{Training Day at Qt Developer Days 2009}.
|
|
||||||
\li The \l{Thread Support in Qt} document is a good starting point into
|
|
||||||
the reference documentation.
|
|
||||||
\li Qt comes with several additional examples for
|
|
||||||
\l{Threading and Concurrent Programming Examples}{QThread and QtConcurrent}.
|
|
||||||
\li Several good books describe how to work with Qt threads. The most
|
|
||||||
extensive coverage can be found in \e{Advanced Qt Programming} by Mark
|
|
||||||
Summerfield, Prentice Hall - roughly 70 of 500 pages cover QThread and
|
|
||||||
QtConcurrent.
|
|
||||||
\endlist
|
|
||||||
*/
|
|
@ -1,828 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
|
||||||
** Contact: http://www.qt-project.org/legal
|
|
||||||
**
|
|
||||||
** This file is part of the documentation of the Qt Toolkit.
|
|
||||||
**
|
|
||||||
** $QT_BEGIN_LICENSE:FDL$
|
|
||||||
** Commercial License Usage
|
|
||||||
** Licensees holding valid commercial Qt licenses may use this file in
|
|
||||||
** accordance with the commercial license agreement provided with the
|
|
||||||
** Software or, alternatively, in accordance with the terms contained in
|
|
||||||
** a written agreement between you and Digia. For licensing terms and
|
|
||||||
** conditions see http://qt.digia.com/licensing. For further information
|
|
||||||
** use the contact form at http://qt.digia.com/contact-us.
|
|
||||||
**
|
|
||||||
** GNU Free Documentation License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU Free
|
|
||||||
** Documentation License version 1.3 as published by the Free Software
|
|
||||||
** Foundation and appearing in the file included in the packaging of
|
|
||||||
** this file. Please review the following information to ensure
|
|
||||||
** the GNU Free Documentation License version 1.3 requirements
|
|
||||||
** will be met: http://www.gnu.org/copyleft/fdl.html.
|
|
||||||
** $QT_END_LICENSE$
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\group thread
|
|
||||||
\title Threading Classes
|
|
||||||
|
|
||||||
These \l{Qt Core} classes provide threading support to applications.
|
|
||||||
The \l{Thread Support in Qt} page covers how to use these classes.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\page threads.html
|
|
||||||
\title Thread Support in Qt
|
|
||||||
\ingroup qt-basic-concepts
|
|
||||||
\brief A detailed discussion of thread handling in Qt.
|
|
||||||
|
|
||||||
\ingroup frameworks-technologies
|
|
||||||
|
|
||||||
\nextpage Multithreading Technologies in Qt
|
|
||||||
|
|
||||||
Qt provides thread support in the form of platform-independent
|
|
||||||
threading classes, a thread-safe way of posting events, and
|
|
||||||
signal-slot connections across threads. This makes it easy to
|
|
||||||
develop portable multithreaded Qt applications and take advantage
|
|
||||||
of multiprocessor machines. Multithreaded programming is also a
|
|
||||||
useful paradigm for performing time-consuming operations without
|
|
||||||
freezing the user interface of an application.
|
|
||||||
|
|
||||||
Earlier versions of Qt offered an option to build the library
|
|
||||||
without thread support. Since Qt 4.0, threads are always enabled.
|
|
||||||
|
|
||||||
\section1 Topics:
|
|
||||||
|
|
||||||
\list
|
|
||||||
\li \l{Recommended Reading}
|
|
||||||
\li \l{The Threading Classes}
|
|
||||||
\li \l{Multithreading Technologies in Qt}
|
|
||||||
\li \l{Synchronizing Threads}
|
|
||||||
\li \l{Reentrancy and Thread-Safety}
|
|
||||||
\li \l{Threads and QObjects}
|
|
||||||
\li \l{Thread-Support in Qt Modules}
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
\section1 Recommended Reading
|
|
||||||
|
|
||||||
This document is intended for an audience that has knowledge of,
|
|
||||||
and experience with, multithreaded applications. If you are new
|
|
||||||
to threading see our Recommended Reading list:
|
|
||||||
|
|
||||||
\list
|
|
||||||
\li \l {http://www.amazon.com/Threads-Primer-Guide-Multithreaded-Programming/dp/0134436989}{Threads Primer: A Guide to Multithreaded Programming}
|
|
||||||
\li \l {http://www.amazon.com/Thread-Time-MultiThreaded-Programming-Guide/dp/0131900676}{Thread Time: The Multithreaded Programming Guide}
|
|
||||||
\li \l {http://www.amazon.com/Pthreads-Programming-Standard-Multiprocessing-Nutshell/dp/1565921151a}{Pthreads Programming: A POSIX Standard for Better Multiprocessing}
|
|
||||||
\li \l {http://www.amazon.com/WIN32-Multithreaded-Programming-Aaron-Cohen/dp/1565922964}{Win32 Multithreaded Programming}
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
\section1 The Threading Classes
|
|
||||||
|
|
||||||
These classes are relevant to threaded applications.
|
|
||||||
|
|
||||||
\annotatedlist thread
|
|
||||||
|
|
||||||
\omit
|
|
||||||
\list
|
|
||||||
\li QThread provides the means to start a new thread.
|
|
||||||
\li QThreadStorage provides per-thread data storage.
|
|
||||||
\li QThreadPool manages a pool of threads that run QRunnable objects.
|
|
||||||
\li QRunnable is an abstract class representing a runnable object.
|
|
||||||
\li QMutex provides a mutual exclusion lock, or mutex.
|
|
||||||
\li QMutexLocker is a convenience class that automatically locks
|
|
||||||
and unlocks a QMutex.
|
|
||||||
\li QReadWriteLock provides a lock that allows simultaneous read access.
|
|
||||||
\li QReadLocker and QWriteLocker are convenience classes that automatically
|
|
||||||
lock and unlock a QReadWriteLock.
|
|
||||||
\li QSemaphore provides an integer semaphore (a generalization of a mutex).
|
|
||||||
\li QWaitCondition provides a way for threads to go to sleep until
|
|
||||||
woken up by another thread.
|
|
||||||
\li QAtomicInt provides atomic operations on integers.
|
|
||||||
\li QAtomicPointer provides atomic operations on pointers.
|
|
||||||
\endlist
|
|
||||||
\endomit
|
|
||||||
|
|
||||||
\note Qt's threading classes are implemented with native threading APIs;
|
|
||||||
e.g., Win32 and pthreads. Therefore, they can be used with threads of the
|
|
||||||
same native API.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\page threads-technologies.html
|
|
||||||
\title Multithreading Technologies in Qt
|
|
||||||
\ingroup qt-basic-concepts
|
|
||||||
\brief An overview and comparison of different ways to use threads in Qt.
|
|
||||||
|
|
||||||
\ingroup frameworks-technologies
|
|
||||||
|
|
||||||
\contentspage Thread Support in Qt
|
|
||||||
\previouspage Thread Support in Qt
|
|
||||||
\nextpage Synchronizing Threads
|
|
||||||
|
|
||||||
Qt offers many classes and functions for working with threads. Below are
|
|
||||||
four different approaches that Qt programmers can use to implement
|
|
||||||
multithreaded applications.
|
|
||||||
|
|
||||||
|
|
||||||
\section1 QThread: Low-Level API with Optional Event Loops
|
|
||||||
|
|
||||||
QThread is the foundation of all thread control in Qt. Each QThread
|
|
||||||
instance represents and controls one thread.
|
|
||||||
|
|
||||||
QThread can either be instantiated directly or subclassed. Instantiating a
|
|
||||||
QThread provides a parallel event loop, allowing QObject slots to be invoked
|
|
||||||
in a secondary thread. Subclassing a QThread allows the application to initialize
|
|
||||||
the new thread before starting its event loop, or to run parallel code
|
|
||||||
without an event loop.
|
|
||||||
|
|
||||||
See the \l{QThread}{QThread class reference} and the \l{Threading and
|
|
||||||
Concurrent Programming Examples}{threading examples} for demonstrations on
|
|
||||||
how to use QThread.
|
|
||||||
|
|
||||||
|
|
||||||
\section1 QThreadPool and QRunnable: Reusing Threads
|
|
||||||
|
|
||||||
Creating and destroying threads frequently can be expensive. To reduce this
|
|
||||||
overhead, existing threads can be reused for new tasks. QThreadPool is a
|
|
||||||
collection of reuseable QThreads.
|
|
||||||
|
|
||||||
To run code in one of a QThreadPool's threads, reimplement QRunnable::run()
|
|
||||||
and instantiate the subclassed QRunnable. Use QThreadPool::start() to put
|
|
||||||
the QRunnable in the QThreadPool's run queue. When a thread becomes available,
|
|
||||||
the code within QRunnable::run() will execute in that thread.
|
|
||||||
|
|
||||||
Each Qt application has a global thread pool, which is accessible through
|
|
||||||
QThreadPool::globalInstance(). This global thread pool automatically maintains
|
|
||||||
an optimal number of threads based on the number of cores in the CPU. However,
|
|
||||||
a separate QThreadPool can be created and managed explicitly.
|
|
||||||
|
|
||||||
|
|
||||||
\section1 Qt Concurrent: Using a High-level API
|
|
||||||
|
|
||||||
The \l{Qt Concurrent} module provides high-level functions that deal with some
|
|
||||||
common parallel computation patterns: map, filter, and reduce. Unlike using
|
|
||||||
QThread and QRunnable, these functions never require the use of \l{Synchronizing
|
|
||||||
Threads#Low-Level Synchronization Primitives}{low-level threading primitives}
|
|
||||||
such as mutexes or semaphores. Instead, they return a QFuture object which can
|
|
||||||
be used to retrieve the functions' results when they are ready. QFuture can
|
|
||||||
also be used to query computation progress and to pause/resume/cancel the
|
|
||||||
computation. For convenience, QFutureWatcher enables interactions with
|
|
||||||
\l{QFuture}s via signals and slots.
|
|
||||||
|
|
||||||
\l{Qt Concurrent}'s map, filter and reduce algorithms automatically distribute
|
|
||||||
computation across all available processor cores, so applications written today
|
|
||||||
will continue to scale when deployed later on a system with more cores.
|
|
||||||
|
|
||||||
This module also provides the QtConcurrent::run() function, which can run any
|
|
||||||
function in another thread. However, QtConcurrent::run() only supports a subset
|
|
||||||
of features available to the map, filter and reduce functions. The QFuture
|
|
||||||
can be used to retrieve the function's return value and to check if the thread
|
|
||||||
is running. However, a call to QtConcurrent::run() uses one thread only, cannot
|
|
||||||
be paused/resumed/canceled, and cannot be queried for progress.
|
|
||||||
|
|
||||||
See the \l{Qt Concurrent} module documentation for details on the individual functions.
|
|
||||||
|
|
||||||
|
|
||||||
\section1 WorkerScript: Threading in QML
|
|
||||||
|
|
||||||
The WorkerScript QML type lets JavaScript code run in parallel with the GUI
|
|
||||||
thread.
|
|
||||||
|
|
||||||
Each WorkerScript instance can have one \c{.js} script attached to it. When
|
|
||||||
WorkerScript::sendMessage() is called, the script will run in a separate thread
|
|
||||||
(and a separate \l{QQmlContext}{QML context}). When the script finishes
|
|
||||||
running, it can send a reply back to the GUI thread which will invoke the
|
|
||||||
WorkerScript::onMessage() signal handler.
|
|
||||||
|
|
||||||
Using a WorkerScript is similar to using a worker QObject that has been moved
|
|
||||||
to another thread. Data is transferred between threads via signals.
|
|
||||||
|
|
||||||
See the WorkerScript documentation for details on how to implement the script,
|
|
||||||
and for a list of data types that can be passed between threads.
|
|
||||||
|
|
||||||
|
|
||||||
\section1 Choosing an Appropriate Approach
|
|
||||||
|
|
||||||
As demonstrated above, Qt provides different solutions for developing threaded
|
|
||||||
applications. The right solution for a given application depends on the purpose
|
|
||||||
of the new thread and the thread's lifetime. Below is a comparison of Qt's
|
|
||||||
threading technologies, followed by recommended solutions for some example use cases.
|
|
||||||
|
|
||||||
\section2 Comparison of Solutions
|
|
||||||
|
|
||||||
\table
|
|
||||||
\header
|
|
||||||
\li Feature
|
|
||||||
\li QThread
|
|
||||||
\li QRunnable and QThreadPool
|
|
||||||
\li QtConcurrent::run()
|
|
||||||
\li Qt Concurrent (Map, Filter, Reduce)
|
|
||||||
\li WorkerScript
|
|
||||||
\row
|
|
||||||
\li API
|
|
||||||
\li C++
|
|
||||||
\li C++
|
|
||||||
\li C++
|
|
||||||
\li C++
|
|
||||||
\li QML
|
|
||||||
\row
|
|
||||||
\li Thread priority can be specified
|
|
||||||
\li Yes
|
|
||||||
\li Yes
|
|
||||||
\li
|
|
||||||
\li
|
|
||||||
\li
|
|
||||||
\row
|
|
||||||
\li Thread can run an event loop
|
|
||||||
\li Yes
|
|
||||||
\li
|
|
||||||
\li
|
|
||||||
\li
|
|
||||||
\li
|
|
||||||
\row
|
|
||||||
\li Thread can receive data updates through signals
|
|
||||||
\li Yes (received by a worker QObject)
|
|
||||||
\li
|
|
||||||
\li
|
|
||||||
\li
|
|
||||||
\li Yes (received by WorkerScript)
|
|
||||||
\row
|
|
||||||
\li Thread can be controlled using signals
|
|
||||||
\li Yes (received by QThread)
|
|
||||||
\li
|
|
||||||
\li
|
|
||||||
\li Yes (received by QFutureWatcher)
|
|
||||||
\li
|
|
||||||
\row
|
|
||||||
\li Thread can be monitored through a QFuture
|
|
||||||
\li
|
|
||||||
\li
|
|
||||||
\li Partially
|
|
||||||
\li Yes
|
|
||||||
\li
|
|
||||||
\row
|
|
||||||
\li Built-in ability to pause/resume/cancel
|
|
||||||
\li
|
|
||||||
\li
|
|
||||||
\li
|
|
||||||
\li Yes
|
|
||||||
\li
|
|
||||||
\endtable
|
|
||||||
|
|
||||||
|
|
||||||
\section2 Example Use Cases
|
|
||||||
|
|
||||||
\table
|
|
||||||
\header
|
|
||||||
\li Lifetime of thread
|
|
||||||
\li Operation
|
|
||||||
\li Solution
|
|
||||||
\row
|
|
||||||
\li One call
|
|
||||||
\li Run a new linear function within another thread, optionally with progress
|
|
||||||
updates during the run.
|
|
||||||
\li Qt provides different solutions:
|
|
||||||
\list
|
|
||||||
\li Place the function in a reimplementation of QThread::run() and
|
|
||||||
start the QThread. Emit signals to update progress. OR
|
|
||||||
\li Place the function in a reimplementation of QRunnable::run() and
|
|
||||||
add the QRunnable to a QThreadPool. Write to a \l{Synchronizing
|
|
||||||
Threads}{thread-safe variable} to update progress. OR
|
|
||||||
\li Run the function using QtConcurrent::run(). Write to a \l{Synchronizing
|
|
||||||
Threads}{thread-safe variable} to update progress.
|
|
||||||
\endlist
|
|
||||||
\row
|
|
||||||
\li One call
|
|
||||||
\li Run an existing function within another thread and get its return value.
|
|
||||||
\li Run the function using QtConcurrent::run(). Have a QFutureWatcher emit
|
|
||||||
the \l{QFutureWatcher::}{finished()} signal when the function has
|
|
||||||
returned, and call QFutureWatcher::result() to get the function's return
|
|
||||||
value.
|
|
||||||
\row
|
|
||||||
\li One call
|
|
||||||
\li Perform an operation on all items of a container, using all available
|
|
||||||
cores. For example, producing thumbnails from a list of images.
|
|
||||||
\li Use Qt Concurrent's \l{QtConcurrent::}{filter()} function to select
|
|
||||||
container elements, and the \l{QtConcurrent::}{map()} function to apply
|
|
||||||
an operation to each element. To fold the output into a single result,
|
|
||||||
use \l{QtConcurrent::}{filteredReduced()} and
|
|
||||||
\l{QtConcurrent::}{mappedReduced()} instead.
|
|
||||||
\row
|
|
||||||
\li One call/Permanent
|
|
||||||
\li Perfrom a long computation in a pure QML application, and update the GUI
|
|
||||||
when the results are ready.
|
|
||||||
\li Place the computation code in a \c{.js} script and attach it to a
|
|
||||||
WorkerScript instance. Call \l{WorkerScript::}{sendMessage()} to start the
|
|
||||||
computation in a new thread. Let the script call WorkerScript::sendMessage()
|
|
||||||
too, to pass the result back to the GUI thread. Handle the result in
|
|
||||||
\l{WorkerScript::}{onMessage} and update the GUI there.
|
|
||||||
\row
|
|
||||||
\li Permanent
|
|
||||||
\li Have an object living in another thread that can perform different
|
|
||||||
tasks upon request and/or can receive new data to work with.
|
|
||||||
\li Subclass a QObject to create a worker. Instantiate this worker object
|
|
||||||
and a QThread. Move the worker to the new thread. Send commands or
|
|
||||||
data to the worker object over queued signal-slot connections.
|
|
||||||
\row
|
|
||||||
\li Permanent
|
|
||||||
\li Repeatedly perform an expensive operation in another thread, where the
|
|
||||||
thread does not need to receive any signals or events.
|
|
||||||
\li Write the infinite loop directly within a reimplementation of QThread::run().
|
|
||||||
Start the thread without an event loop. Let the thread emit signals to
|
|
||||||
send data back to the GUI thread.
|
|
||||||
\endtable
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\page threads-synchronizing.html
|
|
||||||
\title Synchronizing Threads
|
|
||||||
|
|
||||||
\previouspage Multithreading Technologies in Qt
|
|
||||||
\contentspage Thread Support in Qt
|
|
||||||
\nextpage Reentrancy and Thread-Safety
|
|
||||||
|
|
||||||
While the purpose of threads is to allow code to run in parallel,
|
|
||||||
there are times where threads must stop and wait for other
|
|
||||||
threads. For example, if two threads try to write to the same
|
|
||||||
variable simultaneously, the result is undefined. The principle of
|
|
||||||
forcing threads to wait for one another is called \e{mutual exclusion}.
|
|
||||||
It is a common technique for protecting shared resources such as data.
|
|
||||||
|
|
||||||
Qt provides low-level primitives as well as high-level mechanisms
|
|
||||||
for synchronizing threads.
|
|
||||||
|
|
||||||
\section1 Low-Level Synchronization Primitives
|
|
||||||
|
|
||||||
QMutex is the basic class for enforcing mutual exclusion. A thread
|
|
||||||
locks a mutex in order to gain access to a shared resource. If a second
|
|
||||||
thread tries to lock the mutex while it is already locked, the second
|
|
||||||
thread will be put to sleep until the first thread completes its task
|
|
||||||
and unlocks the mutex.
|
|
||||||
|
|
||||||
QReadWriteLock is similar to QMutex, except that it distinguishes
|
|
||||||
between "read" and "write" access. When a piece of data is not being
|
|
||||||
written to, it is safe for multiple threads to read from it simultaneously.
|
|
||||||
A QMutex forces multiple readers to take turns to read shared data, but a
|
|
||||||
QReadWriteLock allows simultaneous reading, thus improving parallelism.
|
|
||||||
|
|
||||||
QSemaphore is a generalization of QMutex that protects a certain
|
|
||||||
number of identical resources. In contrast, a QMutex protects
|
|
||||||
exactly one resource. The \l{Semaphores Example} shows a typical application
|
|
||||||
of semaphores: synchronizing access to a circular buffer between a producer
|
|
||||||
and a consumer.
|
|
||||||
|
|
||||||
QWaitCondition synchronizes threads not by enforcing mutual exclusion but by
|
|
||||||
providing a \e{condition variable}. While the other primitives make threads
|
|
||||||
wait until a resource is unlocked, QWaitCondition makes threads wait until a
|
|
||||||
particular condition has been met. To allow the waiting threads to proceed,
|
|
||||||
call \l{QWaitCondition::wakeOne()}{wakeOne()} to wake one randomly
|
|
||||||
selected thread or \l{QWaitCondition::wakeAll()}{wakeAll()} to wake them all
|
|
||||||
simultaneously. The \l{Wait Conditions Example} shows how to solve the
|
|
||||||
producer-consumer problem using QWaitCondition instead of QSemaphore.
|
|
||||||
|
|
||||||
\note Qt's synchronization classes rely on the use of properly
|
|
||||||
aligned pointers. For instance, you cannot use packed classes with
|
|
||||||
MSVC.
|
|
||||||
|
|
||||||
These synchronization classes can be used to make a method thread safe.
|
|
||||||
However, doing so incurs a performance penalty, which is why most Qt methods
|
|
||||||
are not made thread safe.
|
|
||||||
|
|
||||||
\section2 Risks
|
|
||||||
|
|
||||||
If a thread locks a resource but does not unlock it, the application may
|
|
||||||
freeze because the resource will become permanently unavailable to other threads.
|
|
||||||
This can happen, for example, if an exception is thrown and forces the current
|
|
||||||
function to return without releasing its lock.
|
|
||||||
|
|
||||||
Another similar scenario is a \e{deadlock}. For example, suppose that
|
|
||||||
thread A is waiting for thread B to unlock a resource. If thread B is also
|
|
||||||
waiting for thread A to unlock a different resource, then both threads will
|
|
||||||
end up waiting forever, so the application will freeze.
|
|
||||||
|
|
||||||
\section2 Convenience classes
|
|
||||||
|
|
||||||
QMutexLocker, QReadLocker and QWriteLocker are convenience classes that make it
|
|
||||||
easier to use QMutex and QReadWriteLock. They lock a resource when they are
|
|
||||||
constructed, and automatically unlock it when they are destroyed. They are
|
|
||||||
designed to simplify code that use QMutex and QReadWriteLock, thus reducing
|
|
||||||
the chances that a resource becomes permanently locked by accident.
|
|
||||||
|
|
||||||
\section1 High-Level Event Queues
|
|
||||||
|
|
||||||
Qt's \l{The Event System}{event system} is very useful for inter-thread
|
|
||||||
communication. Every thread may have its own event loop. To call a slot (or
|
|
||||||
any \l{Q_INVOKABLE}{invokable} method) in another thread, place that call in
|
|
||||||
the target thread's event loop. This lets the target thread finish its current
|
|
||||||
task before the slot starts running, while the original thread continues
|
|
||||||
running in parallel.
|
|
||||||
|
|
||||||
To place an invocation in an event loop, make a queued \l{Signals & Slots}
|
|
||||||
{signal-slot} connection. Whenever the signal is emitted, its arguments will
|
|
||||||
be recorded by the event system. The thread that the signal receiver
|
|
||||||
\l{QObject#Thread Affinity}{lives in} will then run the slot. Alternatively,
|
|
||||||
call QMetaObject::invokeMethod() to achieve the same effect without signals.
|
|
||||||
In both cases, a \l{Qt::QueuedConnection}{queued connection} must be used
|
|
||||||
because a \l{Qt::DirectConnection}{direct connection} bypasses the event
|
|
||||||
system and runs the method immediately in the current thread.
|
|
||||||
|
|
||||||
There is no risk of deadlocks when using the event system for thread
|
|
||||||
synchronization, unlike using low-level primitives. However, the event system
|
|
||||||
does not enforce mutual exclusion. If invokable methods access shared data,
|
|
||||||
they must still be protected with low-level primitives.
|
|
||||||
|
|
||||||
Having said that, Qt's event system, along with \l{Implicit Sharing}{implicitly
|
|
||||||
shared} data structures, offers an alternative to traditional thread locking.
|
|
||||||
If signals and slots are used exclusively and no variables are shared between
|
|
||||||
threads, a multithreaded program can do without low-level primitives altogether.
|
|
||||||
|
|
||||||
\sa QThread::exec(), {Threads and QObjects}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\page threads-reentrancy.html
|
|
||||||
\title Reentrancy and Thread-Safety
|
|
||||||
|
|
||||||
\keyword reentrant
|
|
||||||
\keyword thread-safe
|
|
||||||
|
|
||||||
\previouspage Synchronizing Threads
|
|
||||||
\contentspage Thread Support in Qt
|
|
||||||
\nextpage Threads and QObjects
|
|
||||||
|
|
||||||
Throughout the documentation, the terms \e{reentrant} and
|
|
||||||
\e{thread-safe} are used to mark classes and functions to indicate
|
|
||||||
how they can be used in multithread applications:
|
|
||||||
|
|
||||||
\list
|
|
||||||
\li A \e thread-safe function can be called simultaneously from
|
|
||||||
multiple threads, even when the invocations use shared data,
|
|
||||||
because all references to the shared data are serialized.
|
|
||||||
\li A \e reentrant function can also be called simultaneously from
|
|
||||||
multiple threads, but only if each invocation uses its own data.
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
Hence, a \e{thread-safe} function is always \e{reentrant}, but a
|
|
||||||
\e{reentrant} function is not always \e{thread-safe}.
|
|
||||||
|
|
||||||
By extension, a class is said to be \e{reentrant} if its member
|
|
||||||
functions can be called safely from multiple threads, as long as
|
|
||||||
each thread uses a \e{different} instance of the class. The class
|
|
||||||
is \e{thread-safe} if its member functions can be called safely
|
|
||||||
from multiple threads, even if all the threads use the \e{same}
|
|
||||||
instance of the class.
|
|
||||||
|
|
||||||
\note Qt classes are only documented as \e{thread-safe} if they
|
|
||||||
are intended to be used by multiple threads. If a function is not
|
|
||||||
marked as thread-safe or reentrant, it should not be used from
|
|
||||||
different threads. If a class is not marked as thread-safe or
|
|
||||||
reentrant then a specific instance of that class should not be
|
|
||||||
accessed from different threads.
|
|
||||||
|
|
||||||
\section1 Reentrancy
|
|
||||||
|
|
||||||
C++ classes are often reentrant, simply because they only access
|
|
||||||
their own member data. Any thread can call a member function on an
|
|
||||||
instance of a reentrant class, as long as no other thread can call
|
|
||||||
a member function on the \e{same} instance of the class at the
|
|
||||||
same time. For example, the \c Counter class below is reentrant:
|
|
||||||
|
|
||||||
\snippet threads/threads.cpp 3
|
|
||||||
\snippet threads/threads.cpp 4
|
|
||||||
|
|
||||||
The class isn't thread-safe, because if multiple threads try to
|
|
||||||
modify the data member \c n, the result is undefined. This is
|
|
||||||
because the \c ++ and \c -- operators aren't always atomic.
|
|
||||||
Indeed, they usually expand to three machine instructions:
|
|
||||||
|
|
||||||
\list 1
|
|
||||||
\li Load the variable's value in a register.
|
|
||||||
\li Increment or decrement the register's value.
|
|
||||||
\li Store the register's value back into main memory.
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
If thread A and thread B load the variable's old value
|
|
||||||
simultaneously, increment their register, and store it back, they
|
|
||||||
end up overwriting each other, and the variable is incremented
|
|
||||||
only once!
|
|
||||||
|
|
||||||
\section1 Thread-Safety
|
|
||||||
|
|
||||||
Clearly, the access must be serialized: Thread A must perform
|
|
||||||
steps 1, 2, 3 without interruption (atomically) before thread B
|
|
||||||
can perform the same steps; or vice versa. An easy way to make
|
|
||||||
the class thread-safe is to protect all access to the data
|
|
||||||
members with a QMutex:
|
|
||||||
|
|
||||||
\snippet threads/threads.cpp 5
|
|
||||||
\snippet threads/threads.cpp 6
|
|
||||||
|
|
||||||
The QMutexLocker class automatically locks the mutex in its
|
|
||||||
constructor and unlocks it when the destructor is invoked, at the
|
|
||||||
end of the function. Locking the mutex ensures that access from
|
|
||||||
different threads will be serialized. The \c mutex data member is
|
|
||||||
declared with the \c mutable qualifier because we need to lock
|
|
||||||
and unlock the mutex in \c value(), which is a const function.
|
|
||||||
|
|
||||||
\section1 Notes on Qt Classes
|
|
||||||
|
|
||||||
Many Qt classes are \e{reentrant}, but they are not made
|
|
||||||
\e{thread-safe}, because making them thread-safe would incur the
|
|
||||||
extra overhead of repeatedly locking and unlocking a QMutex. For
|
|
||||||
example, QString is reentrant but not thread-safe. You can safely
|
|
||||||
access \e{different} instances of QString from multiple threads
|
|
||||||
simultaneously, but you can't safely access the \e{same} instance
|
|
||||||
of QString from multiple threads simultaneously (unless you
|
|
||||||
protect the accesses yourself with a QMutex).
|
|
||||||
|
|
||||||
Some Qt classes and functions are thread-safe. These are mainly
|
|
||||||
the thread-related classes (e.g. QMutex) and fundamental functions
|
|
||||||
(e.g. QCoreApplication::postEvent()).
|
|
||||||
|
|
||||||
\note Terminology in the multithreading domain isn't entirely
|
|
||||||
standardized. POSIX uses definitions of reentrant and thread-safe
|
|
||||||
that are somewhat different for its C APIs. When using other
|
|
||||||
object-oriented C++ class libraries with Qt, be sure the
|
|
||||||
definitions are understood.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\page threads-qobject.html
|
|
||||||
\title Threads and QObjects
|
|
||||||
|
|
||||||
\previouspage Reentrancy and Thread Safety
|
|
||||||
\contentspage Thread Support in Qt
|
|
||||||
\nextpage Thread-Support in Qt Modules
|
|
||||||
|
|
||||||
QThread inherits QObject. It emits signals to indicate that the
|
|
||||||
thread started or finished executing, and provides a few slots as
|
|
||||||
well.
|
|
||||||
|
|
||||||
More interesting is that \l{QObject}s can be used in multiple
|
|
||||||
threads, emit signals that invoke slots in other threads, and
|
|
||||||
post events to objects that "live" in other threads. This is
|
|
||||||
possible because each thread is allowed to have its own event
|
|
||||||
loop.
|
|
||||||
|
|
||||||
\section1 QObject Reentrancy
|
|
||||||
|
|
||||||
QObject is reentrant. Most of its non-GUI subclasses, such as
|
|
||||||
QTimer, QTcpSocket, QUdpSocket and QProcess, are also
|
|
||||||
reentrant, making it possible to use these classes from multiple
|
|
||||||
threads simultaneously. Note that these classes are designed to be
|
|
||||||
created and used from within a single thread; creating an object
|
|
||||||
in one thread and calling its functions from another thread is not
|
|
||||||
guaranteed to work. There are three constraints to be aware of:
|
|
||||||
|
|
||||||
\list
|
|
||||||
\li \e{The child of a QObject must always be created in the thread
|
|
||||||
where the parent was created.} This implies, among other
|
|
||||||
things, that you should never pass the QThread object (\c
|
|
||||||
this) as the parent of an object created in the thread (since
|
|
||||||
the QThread object itself was created in another thread).
|
|
||||||
|
|
||||||
\li \e{Event driven objects may only be used in a single thread.}
|
|
||||||
Specifically, this applies to the \l{timers.html}{timer
|
|
||||||
mechanism} and the \l{QtNetwork}{network module}. For example,
|
|
||||||
you cannot start a timer or connect a socket in a thread that
|
|
||||||
is not the \l{QObject::thread()}{object's thread}.
|
|
||||||
|
|
||||||
\li \e{You must ensure that all objects created in a thread are
|
|
||||||
deleted before you delete the QThread.} This can be done
|
|
||||||
easily by creating the objects on the stack in your
|
|
||||||
\l{QThread::run()}{run()} implementation.
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
Although QObject is reentrant, the GUI classes, notably QWidget
|
|
||||||
and all its subclasses, are not reentrant. They can only be used
|
|
||||||
from the main thread. As noted earlier, QCoreApplication::exec()
|
|
||||||
must also be called from that thread.
|
|
||||||
|
|
||||||
In practice, the impossibility of using GUI classes in other
|
|
||||||
threads than the main thread can easily be worked around by
|
|
||||||
putting time-consuming operations in a separate worker thread and
|
|
||||||
displaying the results on screen in the main thread when the
|
|
||||||
worker thread is finished. This is the approach used for
|
|
||||||
implementing the \l{Mandelbrot Example} and
|
|
||||||
the \l{network/blockingfortuneclient}{Blocking Fortune Client}
|
|
||||||
example.
|
|
||||||
|
|
||||||
\section1 Per-Thread Event Loop
|
|
||||||
|
|
||||||
Each thread can have its own event loop. The initial thread
|
|
||||||
starts its event loops using QCoreApplication::exec(); other
|
|
||||||
threads can start an event loop using QThread::exec(). Like
|
|
||||||
QCoreApplication, QThread provides an
|
|
||||||
\l{QThread::exit()}{exit(int)} function and a
|
|
||||||
\l{QThread::quit()}{quit()} slot.
|
|
||||||
|
|
||||||
An event loop in a thread makes it possible for the thread to use
|
|
||||||
certain non-GUI Qt classes that require the presence of an event
|
|
||||||
loop (such as QTimer, QTcpSocket, and QProcess). It also makes it
|
|
||||||
possible to connect signals from any threads to slots of a
|
|
||||||
specific thread. This is explained in more detail in the
|
|
||||||
\l{Signals and Slots Across Threads} section below.
|
|
||||||
|
|
||||||
\image threadsandobjects.png Threads, objects, and event loops
|
|
||||||
|
|
||||||
A QObject instance is said to \e live in the thread in which it
|
|
||||||
is created. Events to that object are dispatched by that thread's
|
|
||||||
event loop. The thread in which a QObject lives is available using
|
|
||||||
QObject::thread().
|
|
||||||
|
|
||||||
Note that for QObjects that are created before QApplication,
|
|
||||||
QObject::thread() returns zero. This means that the main thread
|
|
||||||
will only handle posted events for these objects; other event
|
|
||||||
processing is not done at all for objects with no thread. Use the
|
|
||||||
QObject::moveToThread() function to change the thread affinity for
|
|
||||||
an object and its children (the object cannot be moved if it has a
|
|
||||||
parent).
|
|
||||||
|
|
||||||
Calling \c delete on a QObject from a thread other than the one
|
|
||||||
that \e owns the object (or accessing the object in other ways) is
|
|
||||||
unsafe, unless you guarantee that the object isn't processing
|
|
||||||
events at that moment. Use QObject::deleteLater() instead, and a
|
|
||||||
\l{QEvent::DeferredDelete}{DeferredDelete} event will be posted,
|
|
||||||
which the event loop of the object's thread will eventually pick
|
|
||||||
up. By default, the thread that \e owns a QObject is the thread
|
|
||||||
that \e creates the QObject, but not after QObject::moveToThread()
|
|
||||||
has been called.
|
|
||||||
|
|
||||||
If no event loop is running, events won't be delivered to the
|
|
||||||
object. For example, if you create a QTimer object in a thread but
|
|
||||||
never call \l{QThread::exec()}{exec()}, the QTimer will never emit
|
|
||||||
its \l{QTimer::timeout()}{timeout()} signal. Calling
|
|
||||||
\l{QObject::deleteLater()}{deleteLater()} won't work
|
|
||||||
either. (These restrictions apply to the main thread as well.)
|
|
||||||
|
|
||||||
You can manually post events to any object in any thread at any
|
|
||||||
time using the thread-safe function
|
|
||||||
QCoreApplication::postEvent(). The events will automatically be
|
|
||||||
dispatched by the event loop of the thread where the object was
|
|
||||||
created.
|
|
||||||
|
|
||||||
Event filters are supported in all threads, with the restriction
|
|
||||||
that the monitoring object must live in the same thread as the
|
|
||||||
monitored object. Similarly, QCoreApplication::sendEvent()
|
|
||||||
(unlike \l{QCoreApplication::postEvent()}{postEvent()}) can only
|
|
||||||
be used to dispatch events to objects living in the thread from
|
|
||||||
which the function is called.
|
|
||||||
|
|
||||||
\section1 Accessing QObject Subclasses from Other Threads
|
|
||||||
|
|
||||||
QObject and all of its subclasses are not thread-safe. This
|
|
||||||
includes the entire event delivery system. It is important to keep
|
|
||||||
in mind that the event loop may be delivering events to your
|
|
||||||
QObject subclass while you are accessing the object from another
|
|
||||||
thread.
|
|
||||||
|
|
||||||
If you are calling a function on an QObject subclass that doesn't
|
|
||||||
live in the current thread and the object might receive events,
|
|
||||||
you must protect all access to your QObject subclass's internal
|
|
||||||
data with a mutex; otherwise, you may experience crashes or other
|
|
||||||
undesired behavior.
|
|
||||||
|
|
||||||
Like other objects, QThread objects live in the thread where the
|
|
||||||
object was created -- \e not in the thread that is created when
|
|
||||||
QThread::run() is called. It is generally unsafe to provide slots
|
|
||||||
in your QThread subclass, unless you protect the member variables
|
|
||||||
with a mutex.
|
|
||||||
|
|
||||||
On the other hand, you can safely emit signals from your
|
|
||||||
QThread::run() implementation, because signal emission is
|
|
||||||
thread-safe.
|
|
||||||
|
|
||||||
\section1 Signals and Slots Across Threads
|
|
||||||
|
|
||||||
Qt supports these signal-slot connection types:
|
|
||||||
|
|
||||||
\list
|
|
||||||
|
|
||||||
\li \l{Qt::AutoConnection}{Auto Connection} (default) If the signal is
|
|
||||||
emitted in the thread which the receiving object has affinity then
|
|
||||||
the behavior is the same as the Direct Connection. Otherwise,
|
|
||||||
the behavior is the same as the Queued Connection."
|
|
||||||
|
|
||||||
\li \l{Qt::DirectConnection}{Direct Connection} The slot is invoked
|
|
||||||
immediately, when the signal is emitted. The slot is executed
|
|
||||||
in the emitter's thread, which is not necessarily the
|
|
||||||
receiver's thread.
|
|
||||||
|
|
||||||
\li \l{Qt::QueuedConnection}{Queued Connection} The slot is invoked
|
|
||||||
when control returns to the event loop of the receiver's
|
|
||||||
thread. The slot is executed in the receiver's thread.
|
|
||||||
|
|
||||||
\li \l{Qt::BlockingQueuedConnection}{Blocking Queued Connection}
|
|
||||||
The slot is invoked as for the Queued Connection, except the
|
|
||||||
current thread blocks until the slot returns. \note Using this
|
|
||||||
type to connect objects in the same thread will cause deadlock.
|
|
||||||
|
|
||||||
\li \l{Qt::UniqueConnection}{Unique Connection} The behavior is the
|
|
||||||
same as the Auto Connection, but the connection is made only if
|
|
||||||
it does not duplicate an existing connection. i.e., if the same
|
|
||||||
signal is already connected to the same slot for the same pair
|
|
||||||
of objects, then the connection is not made and connect()
|
|
||||||
returns \c false.
|
|
||||||
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
The connection type can be specified by passing an additional
|
|
||||||
argument to \l{QObject::connect()}{connect()}. Be aware that
|
|
||||||
using direct connections when the sender and receiver live in
|
|
||||||
different threads is unsafe if an event loop is running in the
|
|
||||||
receiver's thread, for the same reason that calling any function
|
|
||||||
on an object living in another thread is unsafe.
|
|
||||||
|
|
||||||
QObject::connect() itself is thread-safe.
|
|
||||||
|
|
||||||
The \l{Mandelbrot Example} uses a queued
|
|
||||||
connection to communicate between a worker thread and the main
|
|
||||||
thread. To avoid freezing the main thread's event loop (and, as a
|
|
||||||
consequence, the application's user interface), all the
|
|
||||||
Mandelbrot fractal computation is done in a separate worker
|
|
||||||
thread. The thread emits a signal when it is done rendering the
|
|
||||||
fractal.
|
|
||||||
|
|
||||||
Similarly, the \l{network/blockingfortuneclient}{Blocking Fortune
|
|
||||||
Client} example uses a separate thread for communicating with
|
|
||||||
a TCP server asynchronously.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\page threads-modules.html
|
|
||||||
\title Thread-Support in Qt Modules
|
|
||||||
|
|
||||||
\previouspage Threads and QObjects
|
|
||||||
\contentspage Thread Support in Qt
|
|
||||||
|
|
||||||
\section1 Threads and the SQL Module
|
|
||||||
|
|
||||||
A connection can only be used from within the thread that created it.
|
|
||||||
Moving connections between threads or creating queries from a different
|
|
||||||
thread is not supported.
|
|
||||||
|
|
||||||
In addition, the third party libraries used by the QSqlDrivers can impose
|
|
||||||
further restrictions on using the SQL Module in a multithreaded program.
|
|
||||||
Consult the manual of your database client for more information
|
|
||||||
|
|
||||||
\section1 Painting in Threads
|
|
||||||
|
|
||||||
QPainter can be used in a thread to paint onto QImage, QPrinter, and
|
|
||||||
QPicture paint devices. Painting onto QPixmaps and QWidgets is \e not
|
|
||||||
supported. On Mac OS X the automatic progress dialog will not be
|
|
||||||
displayed if you are printing from outside the GUI thread.
|
|
||||||
|
|
||||||
Any number of threads can paint at any given time, however only
|
|
||||||
one thread at a time can paint on a given paint device. In other
|
|
||||||
words, two threads can paint at the same time if each paints onto
|
|
||||||
separate QImages, but the two threads cannot paint onto the same
|
|
||||||
QImage at the same time.
|
|
||||||
|
|
||||||
\section1 Threads and Rich Text Processing
|
|
||||||
|
|
||||||
The QTextDocument, QTextCursor, and \l{richtext.html}{all related classes} are reentrant.
|
|
||||||
|
|
||||||
Note that a QTextDocument instance created in the GUI thread may
|
|
||||||
contain QPixmap image resources. Use QTextDocument::clone() to
|
|
||||||
create a copy of the document, and pass the copy to another thread for
|
|
||||||
further processing (such as printing).
|
|
||||||
|
|
||||||
\section1 Threads and the SVG module
|
|
||||||
|
|
||||||
The QSvgGenerator and QSvgRenderer classes in the QtSvg module
|
|
||||||
are reentrant.
|
|
||||||
|
|
||||||
\section1 Threads and Implicitly Shared Classes
|
|
||||||
|
|
||||||
Qt uses an optimization called \l{implicit sharing} for many of
|
|
||||||
its value class, notably QImage and QString. Beginning with Qt 4,
|
|
||||||
implicit shared classes can safely be copied across threads, like
|
|
||||||
any other value classes. They are fully
|
|
||||||
\l{Reentrancy and Thread-Safety}{reentrant}. The implicit sharing
|
|
||||||
is really \e implicit.
|
|
||||||
|
|
||||||
In many people's minds, implicit sharing and multithreading are
|
|
||||||
incompatible concepts, because of the way the reference counting
|
|
||||||
is typically done. Qt, however, uses atomic reference counting to
|
|
||||||
ensure the integrity of the shared data, avoiding potential
|
|
||||||
corruption of the reference counter.
|
|
||||||
|
|
||||||
Note that atomic reference counting does not guarantee
|
|
||||||
\l{Reentrancy and Thread-Safety}{thread-safety}. Proper locking should be used
|
|
||||||
when sharing an instance of an implicitly shared class between
|
|
||||||
threads. This is the same requirement placed on all
|
|
||||||
\l{Reentrancy and Thread-Safety}{reentrant} classes, shared or not. Atomic reference
|
|
||||||
counting does, however, guarantee that a thread working on its
|
|
||||||
own, local instance of an implicitly shared class is safe. We
|
|
||||||
recommend using \l{Signals and Slots Across Threads}{signals and
|
|
||||||
slots} to pass data between threads, as this can be done without
|
|
||||||
the need for any explicit locking.
|
|
||||||
|
|
||||||
To sum it up, implicitly shared classes in Qt 4 are really \e
|
|
||||||
implicitly shared. Even in multithreaded applications, you can
|
|
||||||
safely use them as if they were plain, non-shared, reentrant
|
|
||||||
value-based classes.
|
|
||||||
*/
|
|
@ -27,7 +27,7 @@ qhp.QtXml.subprojects.classes.sortPages = true
|
|||||||
|
|
||||||
tagfile = ../../../doc/qtxml/qtxml.tags
|
tagfile = ../../../doc/qtxml/qtxml.tags
|
||||||
|
|
||||||
depends += qtcore qtnetwork
|
depends += qtcore qtnetwork qtdoc
|
||||||
|
|
||||||
headerdirs += ..
|
headerdirs += ..
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user