diff options
author | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-10-24 12:48:39 +0200 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-10-24 12:48:42 +0200 |
commit | 840f6a40e6218992b5b9d451ee3c0886a4846c89 (patch) | |
tree | 2b808decc7adf5218b810d2de6b45c5a8b4cfc42 /src/corelib/doc | |
parent | 109bf980b37fed405c6c1eb14cb9c83ff897e389 (diff) | |
parent | 2e3870fe37d36ccf4bd84eb90e1d5e08ad00c1bc (diff) |
Merge remote-tracking branch 'origin/stable' into dev
Change-Id: Ie56539b2e0be611a363b5f15ae5412a78d6945a2
Diffstat (limited to 'src/corelib/doc')
-rw-r--r-- | src/corelib/doc/snippets/code/doc_src_containers.cpp | 30 | ||||
-rw-r--r-- | src/corelib/doc/snippets/qloggingcategory/main.cpp | 44 | ||||
-rw-r--r-- | src/corelib/doc/src/containers.qdoc | 14 | ||||
-rw-r--r-- | src/corelib/doc/src/implicit-sharing.qdoc | 20 | ||||
-rw-r--r-- | src/corelib/doc/src/objectmodel/signalsandslots.qdoc | 1 | ||||
-rw-r--r-- | src/corelib/doc/src/threads-basics.qdoc | 25 | ||||
-rw-r--r-- | src/corelib/doc/src/threads.qdoc | 118 |
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 |