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
|
||||
|
||||
depends += qtcore qtnetwork
|
||||
depends += qtcore qtnetwork qtdoc
|
||||
|
||||
headerdirs += ..
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user