summaryrefslogtreecommitdiffstats
path: root/src/corelib/doc
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@digia.com>2013-10-24 12:48:39 +0200
committerFrederik Gladhorn <frederik.gladhorn@digia.com>2013-10-24 12:48:42 +0200
commit840f6a40e6218992b5b9d451ee3c0886a4846c89 (patch)
tree2b808decc7adf5218b810d2de6b45c5a8b4cfc42 /src/corelib/doc
parent109bf980b37fed405c6c1eb14cb9c83ff897e389 (diff)
parent2e3870fe37d36ccf4bd84eb90e1d5e08ad00c1bc (diff)
Merge remote-tracking branch 'origin/stable' into dev
Diffstat (limited to 'src/corelib/doc')
-rw-r--r--src/corelib/doc/snippets/code/doc_src_containers.cpp30
-rw-r--r--src/corelib/doc/snippets/qloggingcategory/main.cpp44
-rw-r--r--src/corelib/doc/src/containers.qdoc14
-rw-r--r--src/corelib/doc/src/implicit-sharing.qdoc20
-rw-r--r--src/corelib/doc/src/objectmodel/signalsandslots.qdoc1
-rw-r--r--src/corelib/doc/src/threads-basics.qdoc25
-rw-r--r--src/corelib/doc/src/threads.qdoc118
7 files changed, 172 insertions, 80 deletions
diff --git a/src/corelib/doc/snippets/code/doc_src_containers.cpp b/src/corelib/doc/snippets/code/doc_src_containers.cpp
index 350b2a91f2..6e59a8a548 100644
--- a/src/corelib/doc/snippets/code/doc_src_containers.cpp
+++ b/src/corelib/doc/snippets/code/doc_src_containers.cpp
@@ -273,3 +273,33 @@ QString onlyLetters(const QString &in)
return out;
}
//! [23]
+
+//! [24]
+QVector<int> a, b;
+a.resize(100000); // make a big vector filled with 0.
+
+QVector<int>::iterator i = a.begin();
+// WRONG way of using the iterator i:
+b = a;
+/*
+ Now we should be careful with iterator i since it will point to shared data
+ If we do *i = 4 then we would change the shared instance (both vectors)
+ The behavior differs from STL containers. Avoid doing such things in Qt.
+*/
+
+a[0] = 5;
+/*
+ Container a is now detached from the shared data,
+ and even though i was an iterator from the container a, it now works as an iterator in b.
+ Here the situation is that (*i) == 0.
+*/
+
+b.clear(); // Now the iterator i is completely invalid.
+
+int j = *i; // Undefined behavior!
+/*
+ The data from b (which i pointed to) is gone.
+ This would be well-defined with STL containers (and (*i) == 5),
+ but with QVector this is likely to crash.
+*/
+//! [24]
diff --git a/src/corelib/doc/snippets/qloggingcategory/main.cpp b/src/corelib/doc/snippets/qloggingcategory/main.cpp
index 27d64e8253..c1dad7f43a 100644
--- a/src/corelib/doc/snippets/qloggingcategory/main.cpp
+++ b/src/corelib/doc/snippets/qloggingcategory/main.cpp
@@ -67,24 +67,45 @@ QList<UsbEntry> usbEntries() {
return entries;
}
-void main(int argc, char *argv[])
+//![20]
+void myCategoryFilter(QLoggingCategory *);
+//![20]
+
+//![21]
+QLoggingCategory::CategoryFilter oldCategoryFilter;
+
+void myCategoryFilter(QLoggingCategory *category)
+{
+ // configure qt.driver.usb category here, otherwise forward to to default filter.
+ if (qstrcmp(category->categoryName(), "qt.driver.usb") == 0)
+ category->setEnabled(QtDebugMsg, true);
+ else
+ oldCategoryFilter(category);
+}
+//![21]
+
+int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//![2]
- // don't run the expensive code if the string won't print
- if (QT_DRIVER_USB().isDebugEnabled()) {
- QStringList items;
- foreach (const UsbEntry &entry, usbEntries())
- items << QString("%1 (%2)").arg(entry.id, entry.classtype);
- qCDebug(QT_DRIVER_USB) << "devices: " << items;
- }
+ QLoggingCategory::setFilterRules(QStringLiteral("qt.driver.usb.debug=true"));
//![2]
+//![22]
+
+// ...
+oldCategoryFilter = QLoggingCategory::installFilter(myCategoryFilter);
+//![22]
+
+//![3]
+ qSetMessagePattern("%{category} %{message}");
//![3]
+
+//![4]
// usbEntries() will only be called if QT_DRIVER_USB category is enabled
qCDebug(QT_DRIVER_USB) << "devices: " << usbEntries();
-//![3]
+//![4]
{
//![10]
@@ -106,8 +127,7 @@ void main(int argc, char *argv[])
qCCritical(category) << "a critical message";
//![12]
}
+
+ return 0;
}
-//![20]
-void myCategoryFilter(QLoggingCategory *);
-//![20]
diff --git a/src/corelib/doc/src/containers.qdoc b/src/corelib/doc/src/containers.qdoc
index ff2df9c020..fa26409d83 100644
--- a/src/corelib/doc/src/containers.qdoc
+++ b/src/corelib/doc/src/containers.qdoc
@@ -533,10 +533,18 @@
This problem doesn't occur with functions that return a const or
non-const reference to a container.
+ \section3 Implicit sharing iterator problem
+
\l{Implicit sharing} has another consequence on STL-style
- iterators: You must not take a copy of a container while
- non-const iterators are active on that container. Java-style
- iterators don't suffer from that limitation.
+ iterators: you should avoid copying a container while
+ iterators are active on that container. The iterators
+ point to an internal structure, and if you copy a container
+ you should be very careful with your iterators. E.g:
+
+ \snippet code/doc_src_containers.cpp 24
+
+ The above example only shows a problem with QVector, but
+ the problem exists for all the implicitly shared Qt containers.
\keyword foreach
\section1 The foreach Keyword
diff --git a/src/corelib/doc/src/implicit-sharing.qdoc b/src/corelib/doc/src/implicit-sharing.qdoc
index 814f8140f3..1185fe8348 100644
--- a/src/corelib/doc/src/implicit-sharing.qdoc
+++ b/src/corelib/doc/src/implicit-sharing.qdoc
@@ -89,9 +89,12 @@
of data. Objects can easily be assigned, sent as function arguments,
and returned from functions.
- Implicit sharing takes place behind the scenes; the programmer
- does not need to worry about it. Even in multithreaded
- applications, implicit sharing takes place, as explained in
+ Implicit sharing mostly takes place behind the scenes;
+ the programmer rarely needs to worry about it. However, Qt's
+ container iterators have different behavior than those from
+ the STL. Read \l{Implicit sharing iterator problem}.
+
+ In multithreaded applications, implicit sharing takes place, as explained in
\l{Thread-Support in Qt Modules#Threads and Implicitly Shared Classes}
{Threads and Implicitly Shared Classes}.
@@ -105,9 +108,10 @@
greater than one. (This is often called \e {copy-on-write} or
\e {value semantics}.)
- An implicitly shared class has total control of its internal data. In
+ An implicitly shared class has control of its internal data. In
any member functions that modify its data, it automatically detaches
- before modifying the data.
+ before modifying the data. Notice, however, the special case with
+ container iterators; see \l{Implicit sharing iterator problem}.
The QPen class, which uses implicit sharing, detaches from the shared
data in all member functions that change the internal data.
@@ -133,9 +137,9 @@
In this example, \c p1 and \c p2 share data until QPainter::begin()
is called for \c p2, because painting a pixmap will modify it.
- \warning Do not copy an implicitly shared container (QMap,
- QVector, etc.) while you are iterating over it using an non-const
- \l{STL-style iterators}{STL-style iterator}.
+ \warning Be careful with copying an implicitly shared container
+ (QMap, QVector, etc.) while you use
+ \l{STL-style iterators}{STL-style iterator}. See \l{Implicit sharing iterator problem}.
\keyword implicitly shared classes
\annotatedlist shared
diff --git a/src/corelib/doc/src/objectmodel/signalsandslots.qdoc b/src/corelib/doc/src/objectmodel/signalsandslots.qdoc
index b86aae830f..dd93b80cae 100644
--- a/src/corelib/doc/src/objectmodel/signalsandslots.qdoc
+++ b/src/corelib/doc/src/objectmodel/signalsandslots.qdoc
@@ -28,6 +28,7 @@
/*!
\page signalsandslots.html
\title Signals & Slots
+ \keyword Signals and Slots
\ingroup qt-basic-concepts
\brief An overview of Qt's signals and slots inter-object
communication mechanism.
diff --git a/src/corelib/doc/src/threads-basics.qdoc b/src/corelib/doc/src/threads-basics.qdoc
index e511c10423..4f381421b4 100644
--- a/src/corelib/doc/src/threads-basics.qdoc
+++ b/src/corelib/doc/src/threads-basics.qdoc
@@ -199,31 +199,6 @@
still important.
On Linux, Valgrind and Helgrind can help detect threading errors.
- The anatomy of QThread is quite interesting:
-
- \list
- \li QThread does not live in the new thread where \l{QThread::}{run()} is
- executed. It lives in the old thread.
- \li Most QThread methods are the thread's control interface and are meant to
- be called from the old thread. Do not move this interface to the newly
- created thread using \l{QObject::}{moveToThread()}; i.e., calling
- \l{QObject::moveToThread()}{moveToThread(this)} is regarded as bad
- practice.
- \li \l{QThread::}{exec()} and the static methods
- \l{QThread::}{usleep()}, \l{QThread::}{msleep()},
- \l{QThread::}{sleep()} are meant to be called from the newly created
- thread.
- \li Additional members defined in the QThread subclass are
- accessible by both threads. The developer is responsible for
- coordinating access. A typical strategy is to set the members before
- \l{QThread::}{start()} is called. Once the worker thread is running,
- the main thread should not touch the additional members anymore. After
- the worker has terminated, the main thread can access the additional
- members again. This is a convenient strategy for passing parameters to a
- thread before it is started as well as for collecting the result once it
- has terminated.
- \endlist
-
\section2 Protecting the Integrity of Data
When writing a multithread application, extra care must be taken to avoid
diff --git a/src/corelib/doc/src/threads.qdoc b/src/corelib/doc/src/threads.qdoc
index 8962dceb01..890fd9f6ff 100644
--- a/src/corelib/doc/src/threads.qdoc
+++ b/src/corelib/doc/src/threads.qdoc
@@ -123,7 +123,7 @@
\nextpage Synchronizing Threads
Qt offers many classes and functions for working with threads. Below are
- three different approaches that Qt programmers can use to implement
+ four different approaches that Qt programmers can use to implement
multithreaded applications.
@@ -163,19 +163,47 @@
\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 QThread
- and QRunnable, these functions do not require the use of low-level threading
- primitives such as mutexes or semaphores. \l {Qt Concurrent} will automatically
- adjust the number of threads used according to the number of processor cores
- available, 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 a thread managed by the global QThreadPool.
+ 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
@@ -187,52 +215,62 @@
\table
\header
- \li Feature/Characteristic
+ \li Feature
\li QThread
- \li QRunnable
- \li Qt Concurrent\sup{*}
+ \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 Supports different thread priorities
+ \li Thread priority can be specified
\li Yes
+ \li Yes
+ \li
\li
\li
\row
- \li Supports an event loop
+ \li Thread can run an event loop
\li Yes
\li
\li
+ \li
+ \li
\row
- \li Supports transferring data to the thread using signals
+ \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 Supports controlling the thread using signals
+ \li Thread can be controlled using signals
\li Yes (received by QThread)
\li
- \li Yes (received by QFutureWatcher)
- \row
- \li Supports thread reuse
\li
- \li Yes
- \li Yes
- \row
- \li Task-oriented
+ \li Yes (received by QFutureWatcher)
\li
- \li Yes
- \li Yes
\row
- \li High level API
+ \li Thread can be monitored through a QFuture
\li
\li
+ \li Partially
\li Yes
+ \li
\row
- \li Supports pausing/resuming/canceling
+ \li Built-in ability to pause/resume/cancel
+ \li
\li
\li
\li Yes
+ \li
\endtable
- \sup{\e{*Except QtConcurrent::run(), which is like QRunnable}}
\section2 Example Use Cases
@@ -244,7 +282,7 @@
\li Solution
\row
\li One call
- \li Run a linear function within another thread, optionally with progress
+ \li Run a new linear function within another thread, optionally with progress
updates during the run.
\li Qt provides different solutions:
\list
@@ -258,13 +296,29 @@
\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::}{filterReduced()} and \l{QtConcurrent::}{mapReduced()}
- instead.
+ 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