summaryrefslogtreecommitdiffstats
path: root/src/corelib/doc/src/threads.qdoc
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/doc/src/threads.qdoc')
-rw-r--r--src/corelib/doc/src/threads.qdoc129
1 files changed, 91 insertions, 38 deletions
diff --git a/src/corelib/doc/src/threads.qdoc b/src/corelib/doc/src/threads.qdoc
index c250f7466b..8962dceb01 100644
--- a/src/corelib/doc/src/threads.qdoc
+++ b/src/corelib/doc/src/threads.qdoc
@@ -290,49 +290,102 @@
\contentspage Thread Support in Qt
\nextpage Reentrancy and Thread-Safety
- The QMutex, QReadWriteLock, QSemaphore, and QWaitCondition
- classes provide means to synchronize threads. While the main idea
- with threads is that they should be as concurrent as possible,
- there are points where threads must stop and wait for other
- threads. For example, if two threads try to access the same
- global variable simultaneously, the results are usually
- undefined.
-
- QMutex provides a mutually exclusive lock, or mutex. At most one
- thread can hold the mutex at any time. If a thread tries to
- acquire the mutex while the mutex is already locked, the thread will
- be put to sleep until the thread that currently holds the mutex
- unlocks it. Mutexes are often used to protect accesses to shared
- data (i.e., data that can be accessed from multiple threads
- simultaneously). In the \l{Reentrancy and Thread-Safety} section
- below, we will use it to make a class thread-safe.
+ 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 to shared data and allows
- multiple readers to access the data simultaneously. Using
- QReadWriteLock instead of QMutex when it is possible can make
- multithreaded programs more concurrent.
+ 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 mutex protects
- exactly one resource. The \l{threads/semaphores}{Semaphores}
- example shows a typical application of semaphores: synchronizing
- access to a circular buffer between a producer and a consumer.
-
- QWaitCondition allows a thread to wake up other threads when some
- condition has been met. One or many threads can block waiting for
- a QWaitCondition to set a condition with
- \l{QWaitCondition::wakeOne()}{wakeOne()} or
- \l{QWaitCondition::wakeAll()}{wakeAll()}. Use
- \l{QWaitCondition::wakeOne()}{wakeOne()} to wake one randomly
- selected event or \l{QWaitCondition::wakeAll()}{wakeAll()} to
- wake them all. The \l{threads/waitconditions}{Wait Conditions}
- example shows how to solve the producer-consumer problem using
- QWaitCondition instead of QSemaphore.
-
- Note that Qt's synchronization classes rely on the use of properly
+ 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 a 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 QReadWriteLocker, 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}
*/
/*!
@@ -618,7 +671,7 @@
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 false.
+ returns \c false.
\endlist