Merge remote-tracking branch 'origin/stable' into dev
Conflicts: src/corelib/tools/qstring.cpp Change-Id: Ifc6cd3a0f1cf14cc0fe6cf30afb0c7f40cfdbc3e
This commit is contained in:
commit
8c6755aeec
@ -49,7 +49,6 @@ static const int ConnectTimeout = 60 * 1000;
|
|||||||
static const int KeepAliveInterval = 30 * 1000;
|
static const int KeepAliveInterval = 30 * 1000;
|
||||||
static const int RateControlTimerDelay = 2000;
|
static const int RateControlTimerDelay = 2000;
|
||||||
static const int MinimalHeaderSize = 48;
|
static const int MinimalHeaderSize = 48;
|
||||||
static const int FullHeaderSize = 68;
|
|
||||||
static const char ProtocolId[] = "BitTorrent protocol";
|
static const char ProtocolId[] = "BitTorrent protocol";
|
||||||
static const char ProtocolIdSize = 19;
|
static const char ProtocolIdSize = 19;
|
||||||
|
|
||||||
|
@ -64,7 +64,6 @@ static const int RateControlTimerDelay = 1000;
|
|||||||
static const int MinimumTimeBeforeRevisit = 30;
|
static const int MinimumTimeBeforeRevisit = 30;
|
||||||
static const int MaxUploads = 4;
|
static const int MaxUploads = 4;
|
||||||
static const int UploadScheduleInterval = 10000;
|
static const int UploadScheduleInterval = 10000;
|
||||||
static const int EndGamePieces = 5;
|
|
||||||
|
|
||||||
class TorrentPiece {
|
class TorrentPiece {
|
||||||
public:
|
public:
|
||||||
|
@ -44,8 +44,6 @@
|
|||||||
#include <QtGui/QImage>
|
#include <QtGui/QImage>
|
||||||
#include <QtCore/QPropertyAnimation>
|
#include <QtCore/QPropertyAnimation>
|
||||||
|
|
||||||
static const qreal FACE_SIZE = 0.4;
|
|
||||||
|
|
||||||
static const qreal speeds[] = { 3.8f, 4.4f, 5.6f };
|
static const qreal speeds[] = { 3.8f, 4.4f, 5.6f };
|
||||||
static const qreal amplitudes[] = { 2.0f, 2.5f, 3.0f };
|
static const qreal amplitudes[] = { 2.0f, 2.5f, 3.0f };
|
||||||
|
|
||||||
|
@ -49,10 +49,7 @@
|
|||||||
static const qreal tee_height = 0.311126;
|
static const qreal tee_height = 0.311126;
|
||||||
static const qreal cross_width = 0.25;
|
static const qreal cross_width = 0.25;
|
||||||
static const qreal bar_thickness = 0.113137;
|
static const qreal bar_thickness = 0.113137;
|
||||||
static const qreal inside_diam = 0.20;
|
|
||||||
static const qreal outside_diam = 0.30;
|
|
||||||
static const qreal logo_depth = 0.10;
|
static const qreal logo_depth = 0.10;
|
||||||
static const int num_divisions = 32;
|
|
||||||
|
|
||||||
//! [0]
|
//! [0]
|
||||||
struct Geometry
|
struct Geometry
|
||||||
|
@ -142,7 +142,7 @@ void MainWindow::showAlbumDetails(QModelIndex index)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!trackList->count() == 0)
|
if (trackList->count() != 0)
|
||||||
trackList->show();
|
trackList->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,10 +44,7 @@
|
|||||||
* demonstrates use of QThread, says hello in another thread and terminates
|
* demonstrates use of QThread, says hello in another thread and terminates
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//! [1]
|
|
||||||
// hellothread/hellothread.cpp
|
|
||||||
void HelloThread::run()
|
void HelloThread::run()
|
||||||
{
|
{
|
||||||
qDebug() << "hello from worker thread " << thread()->currentThreadId();
|
qDebug() << "hello from worker thread " << thread()->currentThreadId();
|
||||||
}
|
}
|
||||||
//! [1]
|
|
||||||
|
@ -42,13 +42,12 @@
|
|||||||
#define HELLOTHREAD_H
|
#define HELLOTHREAD_H
|
||||||
|
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
//! [1]
|
|
||||||
// hellothread/hellothread.h
|
|
||||||
class HelloThread : public QThread
|
class HelloThread : public QThread
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private:
|
private:
|
||||||
void run();
|
void run();
|
||||||
};
|
};
|
||||||
//! [1]
|
|
||||||
#endif // HELLOTHREAD_H
|
#endif // HELLOTHREAD_H
|
||||||
|
@ -41,7 +41,6 @@
|
|||||||
#include <QtCore>
|
#include <QtCore>
|
||||||
#include "hellothread.h"
|
#include "hellothread.h"
|
||||||
|
|
||||||
//! [1]
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
QCoreApplication app(argc, argv);
|
QCoreApplication app(argc, argv);
|
||||||
@ -51,4 +50,3 @@ int main(int argc, char *argv[])
|
|||||||
thread.wait(); // do not exit before the thread is completed!
|
thread.wait(); // do not exit before the thread is completed!
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
//! [1]
|
|
||||||
|
@ -84,7 +84,7 @@ protected:
|
|||||||
virtual QString escapeFilePath(const QString &path) const;
|
virtual QString escapeFilePath(const QString &path) const;
|
||||||
ProString escapeFilePath(const ProString &path) const { return MakefileGenerator::escapeFilePath(path); }
|
ProString escapeFilePath(const ProString &path) const { return MakefileGenerator::escapeFilePath(path); }
|
||||||
bool doPrecompiledHeaders() const { return false; }
|
bool doPrecompiledHeaders() const { return false; }
|
||||||
virtual bool doDepends() const { return false; } //never necesary
|
virtual bool doDepends() const { return writingUnixMakefileGenerator && UnixMakefileGenerator::doDepends(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
inline ProjectBuilderMakefileGenerator::~ProjectBuilderMakefileGenerator()
|
inline ProjectBuilderMakefileGenerator::~ProjectBuilderMakefileGenerator()
|
||||||
|
@ -42,16 +42,6 @@
|
|||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QThreadStorage>
|
#include <QThreadStorage>
|
||||||
|
|
||||||
#include "threads.h"
|
|
||||||
|
|
||||||
//! [0]
|
|
||||||
void MyThread::run()
|
|
||||||
//! [0] //! [1]
|
|
||||||
{
|
|
||||||
//! [1] //! [2]
|
|
||||||
}
|
|
||||||
//! [2]
|
|
||||||
|
|
||||||
#define Counter ReentrantCounter
|
#define Counter ReentrantCounter
|
||||||
|
|
||||||
//! [3]
|
//! [3]
|
||||||
|
@ -1,51 +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:BSD$
|
|
||||||
** You may use this file under the terms of the BSD license as follows:
|
|
||||||
**
|
|
||||||
** "Redistribution and use in source and binary forms, with or without
|
|
||||||
** modification, are permitted provided that the following conditions are
|
|
||||||
** met:
|
|
||||||
** * Redistributions of source code must retain the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer.
|
|
||||||
** * Redistributions in binary form must reproduce the above copyright
|
|
||||||
** notice, this list of conditions and the following disclaimer in
|
|
||||||
** the documentation and/or other materials provided with the
|
|
||||||
** distribution.
|
|
||||||
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
|
||||||
** of its contributors may be used to endorse or promote products derived
|
|
||||||
** from this software without specific prior written permission.
|
|
||||||
**
|
|
||||||
**
|
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
|
||||||
**
|
|
||||||
** $QT_END_LICENSE$
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#include <QThread>
|
|
||||||
|
|
||||||
//! [0]
|
|
||||||
class MyThread : public QThread
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void run();
|
|
||||||
};
|
|
||||||
//! [0]
|
|
@ -172,109 +172,16 @@
|
|||||||
|
|
||||||
\section2 Which Qt Thread Technology Should You Use?
|
\section2 Which Qt Thread Technology Should You Use?
|
||||||
|
|
||||||
Sometimes you want to do more than just running a method in the context of
|
See the \l{Multithreading Technologies in Qt} page for an introduction to the
|
||||||
another thread. You may want to have an object which lives in another
|
different approaches to multithreading to Qt, and for guidelines on how to
|
||||||
thread that provides a service to the GUI thread. Maybe you want another
|
choose among them.
|
||||||
thread to stay alive forever to poll hardware ports and send a signal to
|
|
||||||
the GUI thread when something noteworthy has happened. Qt provides
|
|
||||||
different solutions for developing threaded applications. The right
|
|
||||||
solution depends on the purpose of the new thread as well as on the
|
|
||||||
thread's lifetime.
|
|
||||||
|
|
||||||
\table
|
|
||||||
\header
|
|
||||||
\li Lifetime of thread
|
|
||||||
\li Development task
|
|
||||||
\li Solution
|
|
||||||
\row
|
|
||||||
\li One call
|
|
||||||
\li Run one method within another thread and quit the thread when the
|
|
||||||
method is finished.
|
|
||||||
\li Qt provides different solutions:
|
|
||||||
\list
|
|
||||||
\li Write a function and run it with QtConcurrent::run()
|
|
||||||
\li Derive a class from QRunnable and run it in the global thread
|
|
||||||
pool with QThreadPool::globalInstance()->start()
|
|
||||||
\li Derive a class from QThread, reimplement the QThread::run()
|
|
||||||
method and use QThread::start() to run it.
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
\row
|
|
||||||
\li One call
|
|
||||||
\li Operations are to be performed on all items of a container.
|
|
||||||
Processing should be performed using all available cores. A common
|
|
||||||
example is to produce thumbnails from a list of images.
|
|
||||||
\li QtConcurrent provides the \l{QtConcurrent::}{map()} function for
|
|
||||||
applying operations on every container element,
|
|
||||||
\l{QtConcurrent::}{filter()} for selecting container elements, and
|
|
||||||
the option of specifying a reduce function for combining the
|
|
||||||
remaining elements.
|
|
||||||
\row
|
|
||||||
\li One call
|
|
||||||
\li A long running operation has to be put in another thread. During the
|
|
||||||
course of processing, status information should be sent to the GUI
|
|
||||||
thread.
|
|
||||||
\li Use QThread, reimplement run and emit signals as needed. Connect the
|
|
||||||
signals to the GUI thread's slots using queued signal/slot
|
|
||||||
connections.
|
|
||||||
|
|
||||||
\row
|
|
||||||
\li Permanent
|
|
||||||
\li Have an object living in another thread and let it perform different
|
|
||||||
tasks upon request.
|
|
||||||
This means communication to and from the worker thread is required.
|
|
||||||
\li Derive a class from QObject and implement the necessary slots and
|
|
||||||
signals, move the object to a thread with a running event loop and
|
|
||||||
communicate with the object over queued signal/slot connections.
|
|
||||||
\row
|
|
||||||
\li Permanent
|
|
||||||
\li Have an object living in another thread, let the object perform
|
|
||||||
repeated tasks such as polling a port and enable communication with
|
|
||||||
the GUI thread.
|
|
||||||
\li Same as above but also use a timer in the worker thread to implement
|
|
||||||
polling. However, the best solution for polling is to avoid it
|
|
||||||
completely. Sometimes using QSocketNotifier is an alternative.
|
|
||||||
\endtable
|
|
||||||
|
|
||||||
|
|
||||||
\section1 Qt Thread Basics
|
\section1 Qt Thread Basics
|
||||||
|
|
||||||
QThread is a very convenient cross platform abstraction of native platform
|
The following sections describe how QObjects interact with threads, how
|
||||||
threads. Starting a thread is very simple. Let us look at a short piece of
|
programs can safely access data from multiple threads, and how asynchronous
|
||||||
code that generates another thread which says hello in that thread and then
|
execution produces results without blocking a thread.
|
||||||
exits.
|
|
||||||
|
|
||||||
\snippet ../widgets/tutorials/threads/hellothread/hellothread.h 1
|
|
||||||
|
|
||||||
We derive a class from QThread and reimplement the \l{QThread::}{run()}
|
|
||||||
method.
|
|
||||||
|
|
||||||
\snippet ../widgets/tutorials/threads/hellothread/hellothread.cpp 1
|
|
||||||
|
|
||||||
The run method contains the code that will be run in a separate thread. In
|
|
||||||
this example, a message containing the thread ID will be printed.
|
|
||||||
QThread::start() will call the method in another thread.
|
|
||||||
|
|
||||||
\snippet ../widgets/tutorials/threads/hellothread/main.cpp 1
|
|
||||||
|
|
||||||
To start the thread, our thread object needs to be instantiated. The
|
|
||||||
\l{QThread::}{start()} method creates a new thread and calls the
|
|
||||||
reimplemented \l{QThread::}{run()} method in this new thread. Right after
|
|
||||||
\l{QThread::}{start()} is called, two program counters walk through the
|
|
||||||
program code. The main function starts with only the GUI thread running and
|
|
||||||
it should terminate with only the GUI thread running. Exiting the program
|
|
||||||
when another thread is still busy is a programming error, and therefore,
|
|
||||||
wait is called which blocks the calling thread until the
|
|
||||||
\l{QThread::}{run()} method has completed.
|
|
||||||
|
|
||||||
This is the result of running the code:
|
|
||||||
|
|
||||||
\code
|
|
||||||
//bad code
|
|
||||||
hello from GUI thread 3079423696
|
|
||||||
hello from worker thread 3076111216
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
|
|
||||||
\section2 QObject and Threads
|
\section2 QObject and Threads
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
\ingroup frameworks-technologies
|
\ingroup frameworks-technologies
|
||||||
|
|
||||||
\nextpage Starting Threads with QThread
|
\nextpage Multithreading Technologies in Qt
|
||||||
|
|
||||||
Qt provides thread support in the form of platform-independent
|
Qt provides thread support in the form of platform-independent
|
||||||
threading classes, a thread-safe way of posting events, and
|
threading classes, a thread-safe way of posting events, and
|
||||||
@ -59,7 +59,7 @@
|
|||||||
\list
|
\list
|
||||||
\li \l{Recommended Reading}
|
\li \l{Recommended Reading}
|
||||||
\li \l{The Threading Classes}
|
\li \l{The Threading Classes}
|
||||||
\li \l{Starting Threads with QThread}
|
\li \l{Multithreading Technologies in Qt}
|
||||||
\li \l{Synchronizing Threads}
|
\li \l{Synchronizing Threads}
|
||||||
\li \l{Reentrancy and Thread-Safety}
|
\li \l{Reentrancy and Thread-Safety}
|
||||||
\li \l{Threads and QObjects}
|
\li \l{Threads and QObjects}
|
||||||
@ -112,59 +112,182 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\page threads-starting.html
|
\page threads-technologies.html
|
||||||
\title Starting Threads with QThread
|
\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
|
\contentspage Thread Support in Qt
|
||||||
|
\previouspage Thread Support in Qt
|
||||||
\nextpage Synchronizing Threads
|
\nextpage Synchronizing Threads
|
||||||
|
|
||||||
A QThread instance represents a thread and provides the means to
|
Qt offers many classes and functions for working with threads. Below are
|
||||||
\l{QThread::start()}{start()} a thread, which will then execute the
|
three different approaches that Qt programmers can use to implement
|
||||||
reimplementation of QThread::run(). The \c run() implementation is for a
|
multithreaded applications.
|
||||||
thread what the \c main() entry point is for the application. All code
|
|
||||||
executed in a call stack that starts in the \c run() function is executed
|
|
||||||
by the new thread, and the thread finishes when the function returns.
|
|
||||||
QThread emits signals to indicate that the thread started or finished
|
|
||||||
executing.
|
|
||||||
|
|
||||||
\section1 Creating a Thread
|
|
||||||
|
|
||||||
To create a thread, subclass QThread and reimplement its
|
\section1 QThread: Low-Level API with Optional Event Loops
|
||||||
\l{QThread::run()}{run()} function. For example:
|
|
||||||
|
|
||||||
\snippet threads/threads.h 0
|
QThread is the foundation of all thread control in Qt. Each QThread
|
||||||
\codeline
|
instance represents and controls one thread.
|
||||||
\snippet threads/threads.cpp 0
|
|
||||||
\snippet threads/threads.cpp 1
|
|
||||||
\dots
|
|
||||||
\snippet threads/threads.cpp 2
|
|
||||||
|
|
||||||
\section1 Starting a 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.
|
||||||
|
|
||||||
Then, create an instance of the thread object and call
|
See the \l{QThread}{QThread class reference} and the \l{Threading and
|
||||||
QThread::start(). Note that you must create the QApplication (or
|
Concurrent Programming Examples}{threading examples} for demonstrations on
|
||||||
QCoreApplication) object before you can create a QThread.
|
how to use QThread.
|
||||||
|
|
||||||
The function will return immediately and the
|
|
||||||
main thread will continue. The code that appears in the
|
|
||||||
\l{QThread::run()}{run()} reimplementation will then be executed
|
|
||||||
in a separate thread.
|
|
||||||
|
|
||||||
Creating threads is explained in more detail in the QThread
|
\section1 QThreadPool and QRunnable: Reusing Threads
|
||||||
documentation.
|
|
||||||
|
|
||||||
Note that QCoreApplication::exec() must always be called from the
|
Creating and destroying threads frequently can be expensive. To reduce this
|
||||||
main thread (the thread that executes \c{main()}), not from a
|
overhead, existing threads can be reused for new tasks. QThreadPool is a
|
||||||
QThread. In GUI applications, the main thread is also called the
|
collection of reuseable QThreads.
|
||||||
GUI thread because it's the only thread that is allowed to
|
|
||||||
perform GUI-related operations.
|
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 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.
|
||||||
|
|
||||||
|
See the \l{Qt Concurrent} module documentation for details on the individual functions.
|
||||||
|
|
||||||
|
|
||||||
|
\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/Characteristic
|
||||||
|
\li QThread
|
||||||
|
\li QRunnable
|
||||||
|
\li Qt Concurrent\sup{*}
|
||||||
|
\row
|
||||||
|
\li Supports different thread priorities
|
||||||
|
\li Yes
|
||||||
|
\li
|
||||||
|
\li
|
||||||
|
\row
|
||||||
|
\li Supports an event loop
|
||||||
|
\li Yes
|
||||||
|
\li
|
||||||
|
\li
|
||||||
|
\row
|
||||||
|
\li Supports transferring data to the thread using signals
|
||||||
|
\li Yes (received by a worker QObject)
|
||||||
|
\li
|
||||||
|
\li
|
||||||
|
\row
|
||||||
|
\li Supports controlling the thread 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
|
||||||
|
\li Yes
|
||||||
|
\li Yes
|
||||||
|
\row
|
||||||
|
\li High level API
|
||||||
|
\li
|
||||||
|
\li
|
||||||
|
\li Yes
|
||||||
|
\row
|
||||||
|
\li Supports pausing/resuming/canceling
|
||||||
|
\li
|
||||||
|
\li
|
||||||
|
\li Yes
|
||||||
|
\endtable
|
||||||
|
\sup{\e{*Except QtConcurrent::run(), which is like QRunnable}}
|
||||||
|
|
||||||
|
|
||||||
|
\section2 Example Use Cases
|
||||||
|
|
||||||
|
\table
|
||||||
|
\header
|
||||||
|
\li Lifetime of thread
|
||||||
|
\li Operation
|
||||||
|
\li Solution
|
||||||
|
\row
|
||||||
|
\li One call
|
||||||
|
\li Run a 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 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.
|
||||||
|
\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
|
\page threads-synchronizing.html
|
||||||
\title Synchronizing Threads
|
\title Synchronizing Threads
|
||||||
|
|
||||||
\previouspage Starting Threads with QThread
|
\previouspage Multithreading Technologies in Qt
|
||||||
\contentspage Thread Support in Qt
|
\contentspage Thread Support in Qt
|
||||||
\nextpage Reentrancy and Thread-Safety
|
\nextpage Reentrancy and Thread-Safety
|
||||||
|
|
||||||
|
@ -805,8 +805,7 @@ const QString::Null QString::null = { };
|
|||||||
|
|
||||||
/*! \typedef QString::const_iterator
|
/*! \typedef QString::const_iterator
|
||||||
|
|
||||||
The QString::const_iterator typedef provides an STL-style const
|
This typedef provides an STL-style const iterator for QString.
|
||||||
iterator for QString.
|
|
||||||
|
|
||||||
\sa QString::iterator
|
\sa QString::iterator
|
||||||
*/
|
*/
|
||||||
@ -834,13 +833,12 @@ const QString::Null QString::null = { };
|
|||||||
/*!
|
/*!
|
||||||
\typedef QString::const_reference
|
\typedef QString::const_reference
|
||||||
|
|
||||||
The QString::const_reference typedef provides an STL-style
|
This typedef provides an STL-style const reference for a QString element (QChar).
|
||||||
const reference for a QString element (QChar).
|
|
||||||
*/
|
*/
|
||||||
/*!
|
/*!
|
||||||
\typedef QString::reference
|
\typedef QString::reference
|
||||||
|
|
||||||
The QString::reference typedef provides an STL-style
|
This typedef provides an STL-style
|
||||||
reference for a QString element (QChar).
|
reference for a QString element (QChar).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -860,8 +858,7 @@ const QString::Null QString::null = { };
|
|||||||
/*!
|
/*!
|
||||||
\typedef QString::value_type
|
\typedef QString::value_type
|
||||||
|
|
||||||
The QString::const_reference typedef provides an STL-style
|
This typedef provides an STL-style value type for QString.
|
||||||
value type for QString.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*! \fn QString::iterator QString::begin()
|
/*! \fn QString::iterator QString::begin()
|
||||||
|
@ -104,6 +104,10 @@ public: // typedefs
|
|||||||
{ return QLatin1String(interface) < other; }
|
{ return QLatin1String(interface) < other; }
|
||||||
inline bool operator<(const QByteArray &other) const
|
inline bool operator<(const QByteArray &other) const
|
||||||
{ return interface < other; }
|
{ return interface < other; }
|
||||||
|
#if defined(Q_CC_MSVC) && _MSC_VER < 1600
|
||||||
|
friend inline bool operator<(const QString &str, const AdaptorData &obj)
|
||||||
|
{ return str < QLatin1String(obj.interface); }
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
typedef QVector<AdaptorData> AdaptorMap;
|
typedef QVector<AdaptorData> AdaptorMap;
|
||||||
|
|
||||||
|
@ -804,7 +804,7 @@ bool QDBusConnection::registerObject(const QString &path, QObject *object, Regis
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (options & QDBusConnectionPrivate::VirtualObject) {
|
if (options & QDBusConnectionPrivate::VirtualObject) {
|
||||||
if (options & SubPath && node->activeChildren)
|
if (options & SubPath && !node->children.isEmpty())
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
if ((options & ExportChildObjects && !node->children.isEmpty()))
|
if ((options & ExportChildObjects && !node->children.isEmpty()))
|
||||||
@ -842,7 +842,6 @@ bool QDBusConnection::registerObject(const QString &path, QObject *object, Regis
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// add entry
|
// add entry
|
||||||
++node->activeChildren;
|
|
||||||
node = node->children.insert(it, pathComponents.at(i));
|
node = node->children.insert(it, pathComponents.at(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,16 +140,24 @@ public:
|
|||||||
{
|
{
|
||||||
typedef QVector<ObjectTreeNode> DataList;
|
typedef QVector<ObjectTreeNode> DataList;
|
||||||
|
|
||||||
inline ObjectTreeNode() : obj(0), flags(0), activeChildren(0) { }
|
inline ObjectTreeNode() : obj(0), flags(0) { }
|
||||||
inline ObjectTreeNode(const QString &n) // intentionally implicit
|
inline ObjectTreeNode(const QString &n) // intentionally implicit
|
||||||
: name(n), obj(0), flags(0), activeChildren(0) { }
|
: name(n), obj(0), flags(0) { }
|
||||||
inline ~ObjectTreeNode() { }
|
inline ~ObjectTreeNode() { }
|
||||||
inline bool operator<(const QString &other) const
|
inline bool operator<(const QString &other) const
|
||||||
{ return name < other; }
|
{ return name < other; }
|
||||||
inline bool operator<(const QStringRef &other) const
|
inline bool operator<(const QStringRef &other) const
|
||||||
{ return QStringRef(&name) < other; }
|
{ return QStringRef(&name) < other; }
|
||||||
|
#if defined(Q_CC_MSVC) && _MSC_VER < 1600
|
||||||
|
inline bool operator<(const ObjectTreeNode &other) const
|
||||||
|
{ return name < other.name; }
|
||||||
|
friend inline bool operator<(const QString &str, const ObjectTreeNode &obj)
|
||||||
|
{ return str < obj.name; }
|
||||||
|
friend inline bool operator<(const QStringRef &str, const ObjectTreeNode &obj)
|
||||||
|
{ return str < QStringRef(&obj.name); }
|
||||||
|
#endif
|
||||||
inline bool isActive() const
|
inline bool isActive() const
|
||||||
{ return obj || activeChildren; }
|
{ return obj || !children.isEmpty(); }
|
||||||
|
|
||||||
QString name;
|
QString name;
|
||||||
union {
|
union {
|
||||||
@ -157,7 +165,6 @@ public:
|
|||||||
QDBusVirtualObject *treeNode;
|
QDBusVirtualObject *treeNode;
|
||||||
};
|
};
|
||||||
int flags;
|
int flags;
|
||||||
int activeChildren;
|
|
||||||
|
|
||||||
DataList children;
|
DataList children;
|
||||||
};
|
};
|
||||||
|
@ -587,46 +587,22 @@ bool QDBusConnectionPrivate::handleMessage(const QDBusMessage &amsg)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void garbageCollectChildren(QDBusConnectionPrivate::ObjectTreeNode &node)
|
|
||||||
{
|
|
||||||
int size = node.children.count();
|
|
||||||
if (node.activeChildren == 0) {
|
|
||||||
// easy case
|
|
||||||
node.children.clear();
|
|
||||||
} else if (size > node.activeChildren * 3 || (size > 20 && size * 2 > node.activeChildren * 3)) {
|
|
||||||
// rewrite the vector, keeping only the active children
|
|
||||||
// if the vector is large (> 20 items) and has one third of inactives
|
|
||||||
// or if the vector is small and has two thirds of inactives.
|
|
||||||
QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator end = node.children.end();
|
|
||||||
QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it = node.children.begin();
|
|
||||||
QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator tgt = it;
|
|
||||||
for ( ; it != end; ++it) {
|
|
||||||
if (it->isActive())
|
|
||||||
*tgt++ = qMove(*it);
|
|
||||||
}
|
|
||||||
++tgt;
|
|
||||||
node.children.erase(tgt, end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void huntAndDestroy(QObject *needle, QDBusConnectionPrivate::ObjectTreeNode &haystack)
|
static void huntAndDestroy(QObject *needle, QDBusConnectionPrivate::ObjectTreeNode &haystack)
|
||||||
{
|
{
|
||||||
QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it = haystack.children.begin();
|
QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it = haystack.children.begin();
|
||||||
QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator end = haystack.children.end();
|
|
||||||
for ( ; it != end; ++it) {
|
while (it != haystack.children.end()) {
|
||||||
if (!it->isActive())
|
|
||||||
continue;
|
|
||||||
huntAndDestroy(needle, *it);
|
huntAndDestroy(needle, *it);
|
||||||
if (!it->isActive())
|
if (!it->isActive())
|
||||||
--haystack.activeChildren;
|
it = haystack.children.erase(it);
|
||||||
|
else
|
||||||
|
it++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needle == haystack.obj) {
|
if (needle == haystack.obj) {
|
||||||
haystack.obj = 0;
|
haystack.obj = 0;
|
||||||
haystack.flags = 0;
|
haystack.flags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
garbageCollectChildren(haystack);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void huntAndUnregister(const QStringList &pathComponents, int i, QDBusConnection::UnregisterMode mode,
|
static void huntAndUnregister(const QStringList &pathComponents, int i, QDBusConnection::UnregisterMode mode,
|
||||||
@ -639,7 +615,6 @@ static void huntAndUnregister(const QStringList &pathComponents, int i, QDBusCon
|
|||||||
|
|
||||||
if (mode == QDBusConnection::UnregisterTree) {
|
if (mode == QDBusConnection::UnregisterTree) {
|
||||||
// clear the sub-tree as well
|
// clear the sub-tree as well
|
||||||
node->activeChildren = 0;
|
|
||||||
node->children.clear(); // can't disconnect the objects because we really don't know if they can
|
node->children.clear(); // can't disconnect the objects because we really don't know if they can
|
||||||
// be found somewhere else in the path too
|
// be found somewhere else in the path too
|
||||||
}
|
}
|
||||||
@ -648,14 +623,12 @@ static void huntAndUnregister(const QStringList &pathComponents, int i, QDBusCon
|
|||||||
QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator end = node->children.end();
|
QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator end = node->children.end();
|
||||||
QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it =
|
QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it =
|
||||||
std::lower_bound(node->children.begin(), end, pathComponents.at(i));
|
std::lower_bound(node->children.begin(), end, pathComponents.at(i));
|
||||||
if (it == end || it->name != pathComponents.at(i) || !it->isActive())
|
if (it == end || it->name != pathComponents.at(i))
|
||||||
return; // node not found
|
return; // node not found
|
||||||
|
|
||||||
huntAndUnregister(pathComponents, i + 1, mode, it);
|
huntAndUnregister(pathComponents, i + 1, mode, it);
|
||||||
if (!it->isActive())
|
if (!it->isActive())
|
||||||
--node->activeChildren;
|
node->children.erase(it);
|
||||||
|
|
||||||
garbageCollectChildren(*node);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,6 @@ QT_END_NAMESPACE
|
|||||||
Qt::KeyboardModifiers currentWheelModifiers;
|
Qt::KeyboardModifiers currentWheelModifiers;
|
||||||
bool m_subscribesForGlobalFrameNotifications;
|
bool m_subscribesForGlobalFrameNotifications;
|
||||||
QCocoaGLContext *m_glContext;
|
QCocoaGLContext *m_glContext;
|
||||||
bool m_drawRectHasBeenCalled;
|
|
||||||
bool m_shouldSetGLContextinDrawRect;
|
bool m_shouldSetGLContextinDrawRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,6 @@ static QTouchDevice *touchDevice = 0;
|
|||||||
m_sendKeyEvent = false;
|
m_sendKeyEvent = false;
|
||||||
m_subscribesForGlobalFrameNotifications = false;
|
m_subscribesForGlobalFrameNotifications = false;
|
||||||
m_glContext = 0;
|
m_glContext = 0;
|
||||||
m_drawRectHasBeenCalled = false;
|
|
||||||
m_shouldSetGLContextinDrawRect = false;
|
m_shouldSetGLContextinDrawRect = false;
|
||||||
currentCustomDragTypes = 0;
|
currentCustomDragTypes = 0;
|
||||||
m_sendUpAsRightButton = false;
|
m_sendUpAsRightButton = false;
|
||||||
@ -154,9 +153,9 @@ static QTouchDevice *touchDevice = 0;
|
|||||||
- (void) setQCocoaGLContext:(QCocoaGLContext *)context
|
- (void) setQCocoaGLContext:(QCocoaGLContext *)context
|
||||||
{
|
{
|
||||||
m_glContext = context;
|
m_glContext = context;
|
||||||
if (m_drawRectHasBeenCalled) {
|
|
||||||
[m_glContext->nsOpenGLContext() setView:self];
|
[m_glContext->nsOpenGLContext() setView:self];
|
||||||
} else {
|
if (![m_glContext->nsOpenGLContext() view]) {
|
||||||
|
//was unable to set view
|
||||||
m_shouldSetGLContextinDrawRect = true;
|
m_shouldSetGLContextinDrawRect = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,8 +392,6 @@ static QTouchDevice *touchDevice = 0;
|
|||||||
m_shouldSetGLContextinDrawRect = false;
|
m_shouldSetGLContextinDrawRect = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_drawRectHasBeenCalled = true;
|
|
||||||
|
|
||||||
if (!m_backingStore)
|
if (!m_backingStore)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -2467,7 +2467,7 @@ void tst_QSettings::testEscapes()
|
|||||||
QString s = QSettingsPrivate::variantToString(v); \
|
QString s = QSettingsPrivate::variantToString(v); \
|
||||||
QCOMPARE(s, escStr); \
|
QCOMPARE(s, escStr); \
|
||||||
QCOMPARE(QVariant(QSettingsPrivate::stringToVariant(escStr)), v); \
|
QCOMPARE(QVariant(QSettingsPrivate::stringToVariant(escStr)), v); \
|
||||||
QVERIFY(val == v.func()); \
|
QVERIFY((val) == v.func()); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define testBadEscape(escStr, vStr) \
|
#define testBadEscape(escStr, vStr) \
|
||||||
|
@ -56,10 +56,11 @@
|
|||||||
#define STRINGPREP_BIDI_LEADTRAIL_NOT_RAL 5
|
#define STRINGPREP_BIDI_LEADTRAIL_NOT_RAL 5
|
||||||
|
|
||||||
struct ushortarray {
|
struct ushortarray {
|
||||||
ushortarray(unsigned short *array = 0)
|
ushortarray() {}
|
||||||
|
template <size_t N>
|
||||||
|
ushortarray(unsigned short (&array)[N])
|
||||||
{
|
{
|
||||||
if (array)
|
memcpy(points, array, N*sizeof(unsigned short));
|
||||||
memcpy(points, array, sizeof(points));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned short points[100];
|
unsigned short points[100];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user