From d9a49edc46beb81a80a94ac07543cf7b86856ed3 Mon Sep 17 00:00:00 2001 From: David Boddie Date: Thu, 24 Feb 2011 20:55:42 +0100 Subject: Doc: Added a threading tutorial. Squashed commit containing changes to documentation during the development of a threading tutorial, written by Roland Wolf. --- .gitignore | 1 + doc/src/getting-started/tutorials.qdoc | 15 +- doc/src/images/thread_clock.png | Bin 0 -> 5964 bytes doc/src/images/threads-examples.png | Bin 0 -> 7966 bytes doc/src/images/threadvisual-example.png | Bin 0 -> 16823 bytes doc/src/qt-webpages.qdoc | 4 + doc/src/tutorials/modelview.qdoc | 2 +- doc/src/tutorials/threads.qdoc | 572 +++++++++++++++++++++ doc/src/tutorials/widgets-tutorial.qdoc | 1 + examples/tutorials/threads/clock/clock.pro | 14 + examples/tutorials/threads/clock/clockthread.cpp | 66 +++ examples/tutorials/threads/clock/clockthread.h | 64 +++ examples/tutorials/threads/clock/main.cpp | 67 +++ .../threads/helloconcurrent/helloconcurrent.cpp | 61 +++ .../threads/helloconcurrent/helloconcurrent.pro | 16 + .../tutorials/threads/hellothread/hellothread.cpp | 53 ++ .../tutorials/threads/hellothread/hellothread.h | 54 ++ .../tutorials/threads/hellothread/hellothread.pro | 17 + examples/tutorials/threads/hellothread/main.cpp | 54 ++ .../threads/hellothreadpool/hellothreadpool.cpp | 65 +++ .../threads/hellothreadpool/hellothreadpool.pro | 17 + examples/tutorials/threads/movedobject/main.cpp | 69 +++ .../tutorials/threads/movedobject/movedobject.pro | 18 + examples/tutorials/threads/movedobject/thread.cpp | 101 ++++ examples/tutorials/threads/movedobject/thread.h | 67 +++ .../tutorials/threads/movedobject/workerobject.cpp | 87 ++++ .../tutorials/threads/movedobject/workerobject.h | 64 +++ examples/tutorials/threads/threads.pro | 8 + examples/tutorials/tutorials.pro | 3 +- 29 files changed, 1551 insertions(+), 9 deletions(-) create mode 100644 doc/src/images/thread_clock.png create mode 100644 doc/src/images/threads-examples.png create mode 100644 doc/src/images/threadvisual-example.png create mode 100644 doc/src/tutorials/threads.qdoc create mode 100755 examples/tutorials/threads/clock/clock.pro create mode 100644 examples/tutorials/threads/clock/clockthread.cpp create mode 100644 examples/tutorials/threads/clock/clockthread.h create mode 100755 examples/tutorials/threads/clock/main.cpp create mode 100755 examples/tutorials/threads/helloconcurrent/helloconcurrent.cpp create mode 100755 examples/tutorials/threads/helloconcurrent/helloconcurrent.pro create mode 100755 examples/tutorials/threads/hellothread/hellothread.cpp create mode 100755 examples/tutorials/threads/hellothread/hellothread.h create mode 100755 examples/tutorials/threads/hellothread/hellothread.pro create mode 100755 examples/tutorials/threads/hellothread/main.cpp create mode 100755 examples/tutorials/threads/hellothreadpool/hellothreadpool.cpp create mode 100755 examples/tutorials/threads/hellothreadpool/hellothreadpool.pro create mode 100755 examples/tutorials/threads/movedobject/main.cpp create mode 100755 examples/tutorials/threads/movedobject/movedobject.pro create mode 100644 examples/tutorials/threads/movedobject/thread.cpp create mode 100644 examples/tutorials/threads/movedobject/thread.h create mode 100644 examples/tutorials/threads/movedobject/workerobject.cpp create mode 100644 examples/tutorials/threads/movedobject/workerobject.h create mode 100644 examples/tutorials/threads/threads.pro diff --git a/.gitignore b/.gitignore index f9a4454..d6ba7b5 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ examples/*/*/* examples/*/*/*[.]app !examples/declarative/* !examples/tutorials/* +!examples/tutorials/*/* !examples/ja_JP/*/* demos/*/* !demos/spectrum/* diff --git a/doc/src/getting-started/tutorials.qdoc b/doc/src/getting-started/tutorials.qdoc index 5cde056..881e5f5 100644 --- a/doc/src/getting-started/tutorials.qdoc +++ b/doc/src/getting-started/tutorials.qdoc @@ -61,7 +61,7 @@ \o{2,1} \l{A Quick Start to Qt Designer}{\bold{Qt Designer}} \o{2,1} \l{Qt Linguist Manual: Programmers#Tutorials}{\bold {Qt Linguist}} \row - \o \image designer-examples.png QtDesigner + \o \image QtDesigner \o A quick guide through \QD showing the basic steps to create a form with this interactive tool. @@ -72,17 +72,18 @@ tools provided for developers, translators and release managers. - \row +\row \o{2,1} \l{modelview.html}{\bold{ModelView}} - \o{2,1} - + \o{2,1} \l{thread-basics.html}{\bold {Threads}} \row \o \image treeview_sml.png ModelView - \o This tutorial gives an introduction to ModelView programming using the Qt cross-platform framework - \o + This tutorial gives an introduction to ModelView programming using the Qt cross-platform framework + + \o \image threads-examples.png Threads \o - + A short tutorial about thread concepts in general and basic Qt classes to handle threads. + \row \o{2,1} \l{QML Tutorial}{\bold QML Tutorial} \o{2,1} \l{QML Advanced Tutorial}{\bold SameGame} diff --git a/doc/src/images/thread_clock.png b/doc/src/images/thread_clock.png new file mode 100644 index 0000000..b8a8aa0 Binary files /dev/null and b/doc/src/images/thread_clock.png differ diff --git a/doc/src/images/threads-examples.png b/doc/src/images/threads-examples.png new file mode 100644 index 0000000..b6e4bcc Binary files /dev/null and b/doc/src/images/threads-examples.png differ diff --git a/doc/src/images/threadvisual-example.png b/doc/src/images/threadvisual-example.png new file mode 100644 index 0000000..2a49874 Binary files /dev/null and b/doc/src/images/threadvisual-example.png differ diff --git a/doc/src/qt-webpages.qdoc b/doc/src/qt-webpages.qdoc index fde8d9a..e915267 100644 --- a/doc/src/qt-webpages.qdoc +++ b/doc/src/qt-webpages.qdoc @@ -260,3 +260,7 @@ \title Qt Coding Style */ +/*! + \externalpage http://qt.nokia.com/developer/learning/online/training/training-day-at-developer-days-2009/ + \title Training Day at Qt Developer Days 2009 +*/ diff --git a/doc/src/tutorials/modelview.qdoc b/doc/src/tutorials/modelview.qdoc index cae7764..efd0ff2 100644 --- a/doc/src/tutorials/modelview.qdoc +++ b/doc/src/tutorials/modelview.qdoc @@ -27,7 +27,7 @@ /*! \page modelview.html - + \ingroup tutorials \startpage {index.html}{Qt Reference Documentation} \title Model/View Tutorial diff --git a/doc/src/tutorials/threads.qdoc b/doc/src/tutorials/threads.qdoc new file mode 100644 index 0000000..1d807a0 --- /dev/null +++ b/doc/src/tutorials/threads.qdoc @@ -0,0 +1,572 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $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 \mdash 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 + \o Make processing faster by making use of multicore processors. + \o 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 + \o Alternative + \o Comment + \row + \o QEventLoop::processEvents() + \o 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 + \o QTimer + \o 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 + \o QSocketNotifier QNetworkAccessManager QIODevice::readyRead() + \o 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. QtConcurrent 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? + + Sometimes you want to do more than just running a method in the context of + another thread. You may want to have an object which lives in another + thread that provides a service to the GUI thread. Maybe you want another + 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 + \o Lifetime of thread + \o Development task + \o Solution + \row + \o One call + \o Run one method within another thread and quit the thread when the + method is finished. + \o Qt provides different solutions: + \list + \o Write a function and run it with QtConcurrent::run() + \o Derive a class from QRunnable and run it in the global thread + pool with QThreadPool::globalInstance()->start() + \o Derive a class from QThread, reimplement the QThread::run() + method and use QThread::start() to run it. + \endlist + + \row + \o One call + \o 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. + \o 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 + \o One call + \o 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. + \o Use QThread, reimplement run and emit signals as needed. Connect the + signals to the GUI thread's slots using queued signal/slot + connections. + + \row + \o Permanent + \o 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. + \o 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 + \o Permanent + \o 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. + \o 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 + + QThread is a very convenient cross platform abstraction of native platform + threads. Starting a thread is very simple. Let us look at a short piece of + code that generates another thread which says hello in that thread and then + exits. + + \snippet examples/tutorials/threads/hellothread/hellothread.h 1 + + We derive a class from QThread and reimplement the \l{QThread::}{run()} + method. + + \snippet examples/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 examples/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: + + \badcode + hello from GUI thread 3079423696 + hello from worker thread 3076111216 + \endcode + + + \section2 QObject and Threads + + A QObject is said to have a \e{thread affinity} or, in other words, that it + lives in a certain thread. This means that, at creation time, QObject saves + a pointer to the current thread. This information becomes relevant when an + event is posted with \l{QCoreApplication::}{postEvent()}. The event will be + put in the corresponding thread's event loop. If the thread where the + QObject lives doesn't have an event loop, the event will never be delivered. + + To start an event loop, \l{QThread::}{exec()} must be called inside + \l{QThread::}{run()}. Thread affinity can be changed using + \l{QObject::}{moveToThread()}. + + As mentioned above, developers must always be careful when calling objects' + methods from other threads. 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. + + The anatomy of QThread is quite interesting: + + \list + \o QThread does not live in the new thread where \l{QThread::}{run()} is + executed. It lives in the old thread. + \o 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. + \o \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. + \o 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 + + A QObject's parent must always be in the same thread. This has a surprising + consequence for objects generated within the \l{QThread::}{run()} method: + + \code + void HelloThread::run() + { + QObject *object1 = new QObject(this); //error, parent must be in the same thread + QObject object2; // OK + QSharedPointer object3(new QObject); // OK + } + \endcode + + \section2 Using a Mutex to Protect the Integrity of Data + + A mutex is an object that has \l{QMutex::}{lock()} and \l{QMutex::}{unlock()} + methods and remembers if it is already locked. A mutex is designed to be + called from multiple threads. \l{QMutex::}{lock()} returns immediately if + the mutex is not locked. The next call from another thread will find the + mutex in a locked state and then \l{QMutex::}{lock()} will block the thread + until the other thread calls \l{QMutex::}{unlock()}. This functionality can + make sure that a code section will be executed by only one thread at a time. + + The following line sketches how a mutex can be used to make a method + thread-safe: + + \code + void Worker::work() + { + this->mutex.lock(); // first thread can pass, other threads will be blocked here + doWork(); + this->mutex.unlock(); + } + \endcode + + What happens if one thread does not unlock a mutex? The result can be a + frozen application. In the example above, an exception might be thrown and + \c{mutex.unlock()} will never be reached. To prevent problems like this, + QMutexLocker should be used. + + \code + void Worker::work() + { + QMutexLocker locker(&mutex); // Locks the mutex and unlocks when locker exits the scope + doWork(); + } + \endcode + + This looks easy, but mutexes introduce a new class of problems: deadlocks. + A deadlock happens when a thread waits for a mutex to become unlocked, but + the mutex remains locked because the owning thread is waiting for the first + thread to unlock it. The result is a frozen application. Mutexes can be + used to make a method thread safe. Most Qt methods aren't thread safe + because there is always a performance penalty when using mutexes. + + It isn't always possible to lock and unlock a mutex in a method. Sometimes + the need to lock spans several calls. For example, modifying a container + with an iterator requires a sequence of several calls which should not be + interrupted by other threads. In such a scenario, locking can be achieved + with a mutex that is kept outside of the object to be manipulated. With an + external mutex, the duration of locking can be adjusted to the needs of the + operation. One disadvantage is that external mutexes aid locking, but do + not enforce it because users of the object may forget to use it. + + \section2 Using the Event Loop to Prevent Data Corruption + + The event loops of Qt are a very valuable tool for inter-thread + communication. Every thread may have its own event loop. A safe way of + calling a slot in another thread is by placing that call in another + thread's event loop. This ensures that the target object finishes the + method that is currently running before another method is started. + + So how is it possible to put a method invocation in an event loop? Qt has + two ways of doing this. One way is via queued signal-slot connections; the + other way is to post an event with QCoreApplication::postEvent(). A queued + signal-slot connection is a signal slot connection that is executed + asynchronously. The internal implementation is based on posted events. The + arguments of the signal are put into the event loop and the signal method + returns immediately. + + The connected slot will be executed at a time which depends on what else is + in the event loop. + + Communication via the event loop eliminates the deadlock problem we face + when using mutexes. This is why we recommend using the event loop rather + than locking an object using a mutex. + + \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 + + This tutorial comes with examples for Qt's three basic ways of working with + threads. Two more examples show how to communicate with a running thread + and how a QObject can be placed in another thread, providing service to the + main thread. + + \list + \o Using QThread as shown \l{Qt thread basics}{above} + \o \l{Example 1: Using the Thread Pool}{Using the global QThreadPool} + \o \l{Example 2: Using QtConcurrent}{Using QtConcurrent} + \o \l{Example 3: Clock}{Communication with the GUI thread} + \o \l{Example 4: A Permanent Thread}{A permanent QObject in another thread + provides service to the main thread} + \endlist + + The following examples can all be compiled and run independently. The source can + be found in the examples directory: examples/tutorials/threads/ + + \section2 Example 1: Using the Thread Pool + + Creating and destroying threads frequently can be expensive. To avoid the + cost of thread creation, a thread pool can be used. A thread pool is a + place where threads can be parked and fetched. We can write the same + "hello thread" program as \l{Qt Thread Basics}{above} using the global + thread pool. We derive a class from QRunnable. The code we want to run in + another thread needs to be placed in the reimplemented QRunnable::run() + method. + + \snippet examples/tutorials/threads/hellothreadpool/hellothreadpool.cpp 1 + + We instantiate Work in main(), locate the global thread pool and use the + QThreadPool::start() method. Now the thread pool runs our worker in another + thread. Using the thread pool has a performance advantage because threads + are not destroyed after they have finished running. They are kept in a pool + and wait to be used again later. + + \section2 Example 2: Using QtConcurrent + + \snippet examples/tutorials/threads/helloconcurrent/helloconcurrent.cpp 1 + + We write a global function hello() to implement the work. QtConcurrent::run() + is used to run the function in another thread. The result is a QFuture. + QFuture provides a method called \l{QFuture::}{waitForFinished()}, which + blocks until the calculation is completed. The real power of QtConcurrent + becomes visible when data can be made available in a container. QtConcurrent + provides several functions that are able to process itemized data on all + available cores simultaneously. The use of QtConcurrent is very similar to + applying an STL algorithm to an STL container. + \l{examples-threadandconcurrent.html}{QtConcurrent Map} is a very short and + clear example about how a container of images can be scaled on all available + cores. The image scaling example uses the blocking variants of the functions + used. For every blocking function there is also a non-blocking, asynchronous + counterpart. Getting results asynchronously is implemented with QFuture and + QFutureWatcher. + + \section2 Example 3: Clock + + \image thread_clock.png "clock" + + We want to produce a clock application. The application has a GUI and a + worker thread. The worker thread checks every 10 milliseconds what time it + is. If the formatted time has changed, the result will be sent to the GUI + thread where it is displayed. + + Of course, this is an overly complicated way of designing a clock and, + actually, a separate thread is unnecessary. We would be better off placing + the timer in the main thread because the calculation made in the timer slot + is very short-lived. This example is purely for instructional use and shows + how to communicate from a worker thread to a GUI thread. Note that + communication in this direction is easy. We only need to add a signal + to QThread and make a queued signal/slot connection to the main thread. + Communication from the GUI to the worker thread is shown in the next + example. + + \snippet examples/tutorials/threads/clock/main.cpp 1 + + We've connected the \c clockThread with the label. The connection must be a + queued signal-slot connection because we want to put the call in the event + loop. + + \snippet examples/tutorials/threads/clock/clockthread.h 1 + + We have derived a class from QThread and declared the \c sendTime() signal. + + \snippet examples/tutorials/threads/clock/clockthread.cpp 1 + + The trickiest part of this example is that the timer is connected to its + slot via a direct connection. A default connection would produce a queued + signal-slot connection because the connected objects live in different + threads; remember that QThread does not live in the thread it creates. + + Still it is safe to access ClockThread::timerHit() from the worker thread + because ClockThread::timerHit() is private and only touches local variables + and a private member that isn't touched by public methods. + QDateTime::currentDateTime() isn't marked as thread-safe in Qt + documentation, however we can get away with using it in this small + example because we know that the QDateTime::currentDateTime() static + method isn't used in any other threads. + + \section2 Example 4: A Permanent Thread + + This example shows how it is possible to have a QObject in a worker thread + that accepts requests from the GUI thread, does polling using a timer and + continuously reports results back to the GUI thread. The actual work + including the polling must be implemented in a class derived from QObject. + We have called this class \c WorkerObject in the code shown below. The + thread-specific code is hidden in a class called \c Thread, derived from + QThread. + \c Thread has two additional public members. The \c launchWorker() member + takes the worker object and moves it to another thread with a started event + loop. + The call blocks for a very short moment until the thread creation operation + is completed, allowing the worker object to be used again on the next line. + The \c Thread class's code is short but somewhat involved, so we only show + how to use the class. + + \snippet examples/tutorials/threads/movedobject/main.cpp 1 + + QMetaObject::invokeMethod() calls a slot via the event loop. The worker + object's methods should not be called directly after the object has been + moved to another thread. We let the worker thread do some work and polling, + and use a timer to shut the application down after 3 seconds. Shutting the + worker down needs some care. We call \c{Thread::stop()} to exit the event + loop. We wait for the thread to terminate and, after this has occurred, we + delete the worker. + + \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 + \o Good video tutorials about threads with Qt can be found in the material + from the \l{Training Day at Qt Developer Days 2009}. + \o The \l{Thread Support in Qt} document is a good starting point into + the reference documentation. + \o Qt comes with several additional examples for + \l{Threading and Concurrent Programming Examples}{QThread and QtConcurrent}. + \o 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 +*/ diff --git a/doc/src/tutorials/widgets-tutorial.qdoc b/doc/src/tutorials/widgets-tutorial.qdoc index 6c5df66..4877339 100644 --- a/doc/src/tutorials/widgets-tutorial.qdoc +++ b/doc/src/tutorials/widgets-tutorial.qdoc @@ -27,6 +27,7 @@ /*! \page widgets-tutorial.html + \ingroup tutorials \title Widgets Tutorial \brief This tutorial covers basic usage of widgets and layouts, showing how they are used to build GUI applications. diff --git a/examples/tutorials/threads/clock/clock.pro b/examples/tutorials/threads/clock/clock.pro new file mode 100755 index 0000000..450bfe4 --- /dev/null +++ b/examples/tutorials/threads/clock/clock.pro @@ -0,0 +1,14 @@ +CONFIG += console +TEMPLATE = app +SOURCES += main.cpp \ + clockthread.cpp +HEADERS += clockthread.h + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/tutorials/threads/clock +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS clock.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/tutorials/threads/clock +INSTALLS += target sources + +symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) + diff --git a/examples/tutorials/threads/clock/clockthread.cpp b/examples/tutorials/threads/clock/clockthread.cpp new file mode 100644 index 0000000..01d3f1f --- /dev/null +++ b/examples/tutorials/threads/clock/clockthread.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples 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 Nokia Corporation 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 +#include "clockthread.h" + + //This class starts another thread where it emits a signal for every new second. + +//! [1] +// clock/clockthread.cpp +void ClockThread::run() +{ + QTimer timer; + connect(&timer, SIGNAL(timeout()), this, SLOT(timerHit()), Qt::DirectConnection); + timer.setInterval(10); + timer.start(); // puts one event in the threads event queue + exec(); + timer.stop(); +} + +void ClockThread::timerHit() +{ + QString newTime= QDateTime::currentDateTime().toString("ddd MMMM d yy, hh:mm:ss"); + if(m_lastTime != newTime ){ + m_lastTime = newTime; + emit sendTime(newTime) ; + } +} +//! [1] diff --git a/examples/tutorials/threads/clock/clockthread.h b/examples/tutorials/threads/clock/clockthread.h new file mode 100644 index 0000000..966dbea --- /dev/null +++ b/examples/tutorials/threads/clock/clockthread.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples 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 Nokia Corporation 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$ +** +****************************************************************************/ + +#ifndef CLOCKTHREAD_H +#define CLOCKTHREAD_H + +#include +#include + + + +//! [1] +// clock/clockthread.h +class ClockThread : public QThread +{ + Q_OBJECT +signals: + void sendTime(QString time); +private: + void run(); + QString m_lastTime; +private slots: + void timerHit(); + +}; +//! [1] +#endif // CLOCKTHREAD_H \ No newline at end of file diff --git a/examples/tutorials/threads/clock/main.cpp b/examples/tutorials/threads/clock/main.cpp new file mode 100755 index 0000000..a0f86d6 --- /dev/null +++ b/examples/tutorials/threads/clock/main.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples 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 Nokia Corporation 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 +#include "clockthread.h" + +//A clock that does time formatting in another thread + +//! [1] +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + // build gui + QWidget widget; + QLabel *label = new QLabel; + QHBoxLayout *layout = new QHBoxLayout(&widget); + layout->addWidget(label); + widget.setWindowTitle("clock"); + + //instantiate thread object + ClockThread clockThread; + QObject::connect(&clockThread, SIGNAL(sendTime(QString)), label, SLOT(setText(QString)), Qt::QueuedConnection); + clockThread.start(); + widget.show(); + app.exec(); + clockThread.quit(); + clockThread.wait(); + return 0; +} +//! [1] diff --git a/examples/tutorials/threads/helloconcurrent/helloconcurrent.cpp b/examples/tutorials/threads/helloconcurrent/helloconcurrent.cpp new file mode 100755 index 0000000..26ee255 --- /dev/null +++ b/examples/tutorials/threads/helloconcurrent/helloconcurrent.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples 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 Nokia Corporation 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 +/* + says hello from main thread and secondary thread using QtConcurrent +*/ + +//! [1] +// helloconcurrent/main.cpp +void hello() +{ + qDebug() << "Hello from thread " << QThread::currentThread(); +} + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + QFuture future = QtConcurrent::run(hello); + qDebug() << "hello from GUI thread " << QThread::currentThread(); + future.waitForFinished(); + return 0; +} +//! [1] diff --git a/examples/tutorials/threads/helloconcurrent/helloconcurrent.pro b/examples/tutorials/threads/helloconcurrent/helloconcurrent.pro new file mode 100755 index 0000000..30e9413 --- /dev/null +++ b/examples/tutorials/threads/helloconcurrent/helloconcurrent.pro @@ -0,0 +1,16 @@ +QT -= gui + +CONFIG += console +CONFIG -= app_bundle +TEMPLATE = app +SOURCES += helloconcurrent.cpp + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/tutorials/threads/helloconcurrent +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS helloconcurrent.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/tutorials/threads/helloconcurrent +INSTALLS += target sources + +symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) + + diff --git a/examples/tutorials/threads/hellothread/hellothread.cpp b/examples/tutorials/threads/hellothread/hellothread.cpp new file mode 100755 index 0000000..01cd0f5 --- /dev/null +++ b/examples/tutorials/threads/hellothread/hellothread.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples 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 Nokia Corporation 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 +#include "hellothread.h" +/* + * demonstrates use of QThread, says hello in another thread and terminates + */ + +//! [1] +// hellothread/hellothread.cpp +void HelloThread::run() +{ + qDebug() << "hello from worker thread " << thread()->currentThreadId(); +} +//! [1] diff --git a/examples/tutorials/threads/hellothread/hellothread.h b/examples/tutorials/threads/hellothread/hellothread.h new file mode 100755 index 0000000..a3202c6 --- /dev/null +++ b/examples/tutorials/threads/hellothread/hellothread.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples 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 Nokia Corporation 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$ +** +****************************************************************************/ + +#ifndef HELLOTHREAD_H +#define HELLOTHREAD_H + +#include +//! [1] +// hellothread/hellothread.h +class HelloThread : public QThread +{ + Q_OBJECT +private: + void run(); +}; +//! [1] +#endif // HELLOTHREAD_H diff --git a/examples/tutorials/threads/hellothread/hellothread.pro b/examples/tutorials/threads/hellothread/hellothread.pro new file mode 100755 index 0000000..fee7025 --- /dev/null +++ b/examples/tutorials/threads/hellothread/hellothread.pro @@ -0,0 +1,17 @@ +QT -= gui + +CONFIG += console +CONFIG -= app_bundle +TEMPLATE = app +SOURCES += main.cpp \ + hellothread.cpp +HEADERS += hellothread.h + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/tutorials/threads/hellothread +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS hellothread.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/tutorials/threads/hellothread +INSTALLS += target sources + +symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) + diff --git a/examples/tutorials/threads/hellothread/main.cpp b/examples/tutorials/threads/hellothread/main.cpp new file mode 100755 index 0000000..9a548ea --- /dev/null +++ b/examples/tutorials/threads/hellothread/main.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples 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 Nokia Corporation 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 +#include "hellothread.h" + +//! [1] +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + HelloThread thread; + thread.start(); + qDebug() << "hello from GUI thread " << app.thread()->currentThreadId(); + thread.wait(); // do not exit before the thread is completed! + return 0; +} +//! [1] diff --git a/examples/tutorials/threads/hellothreadpool/hellothreadpool.cpp b/examples/tutorials/threads/hellothreadpool/hellothreadpool.cpp new file mode 100755 index 0000000..30410a5 --- /dev/null +++ b/examples/tutorials/threads/hellothreadpool/hellothreadpool.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples 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 Nokia Corporation 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 +// A hello world program to demonstrate the use of the global thread pool + +//! [1] +// hellothreadpool/main.cpp +class Work : public QRunnable +{ +public: + void run() + { + qDebug() << "Hello from thread " << QThread::currentThread(); + } +}; + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + Work work; + work.setAutoDelete(false); + QThreadPool *threadPool = QThreadPool::globalInstance(); + threadPool->start(&work); + qDebug() << "hello from GUI thread " << QThread::currentThread(); + threadPool->waitForDone(); + return 0; +} +//! [1] diff --git a/examples/tutorials/threads/hellothreadpool/hellothreadpool.pro b/examples/tutorials/threads/hellothreadpool/hellothreadpool.pro new file mode 100755 index 0000000..9cf9c73 --- /dev/null +++ b/examples/tutorials/threads/hellothreadpool/hellothreadpool.pro @@ -0,0 +1,17 @@ +QT -= gui + +CONFIG += console +CONFIG -= app_bundle +TEMPLATE = app +SOURCES += hellothreadpool.cpp + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/tutorials/threads/hellothreadpool +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS hellothreadpool.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/tutorials/threads/hellothreadpool +INSTALLS += target sources + +symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) + + + diff --git a/examples/tutorials/threads/movedobject/main.cpp b/examples/tutorials/threads/movedobject/main.cpp new file mode 100755 index 0000000..a244316 --- /dev/null +++ b/examples/tutorials/threads/movedobject/main.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples 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 Nokia Corporation 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 +#include "workerobject.h" +#include "thread.h" + +/* + * moves a class derived from QObject (WorkerObject) to another thread + * and calls methods over thread boundaries. + */ + +//![1] +// movedobject/main.cpp +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + Thread thread; + qDebug() << "main thread ID: " << app.thread()->currentThreadId(); + WorkerObject *worker = new WorkerObject; + thread.launchWorker(worker); + QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection); + QMetaObject::invokeMethod(worker, "startPolling", Qt::QueuedConnection, Q_ARG(int, 500)); + //let application produce output for 3 seconds and quit + QTimer::singleShot(3000, &app, SLOT(quit())); + app.exec(); + thread.stop(); + thread.wait(); + delete worker; + return 0; +} +//![1] diff --git a/examples/tutorials/threads/movedobject/movedobject.pro b/examples/tutorials/threads/movedobject/movedobject.pro new file mode 100755 index 0000000..678d1d9 --- /dev/null +++ b/examples/tutorials/threads/movedobject/movedobject.pro @@ -0,0 +1,18 @@ +CONFIG += console +CONFIG -= app_bundle +TEMPLATE = app +SOURCES += main.cpp \ + workerobject.cpp \ + thread.cpp + +HEADERS += \ + workerobject.h \ + thread.h + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/tutorials/threads/movedobject +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS movedobject.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/tutorials/threads/movedobject +INSTALLS += target sources + +symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) diff --git a/examples/tutorials/threads/movedobject/thread.cpp b/examples/tutorials/threads/movedobject/thread.cpp new file mode 100644 index 0000000..6dfe8ff --- /dev/null +++ b/examples/tutorials/threads/movedobject/thread.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples 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 Nokia Corporation 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 "thread.h" + +/* + * QThread derived class with additional capability to move a QObject to the + * new thread, to stop the thread and move the QObject back to the thread where + *it came from. + */ + +Thread::Thread( QObject *parent) + : QThread (parent) +{ + //we need a class that receives signals from other threads and emits a signal in response + shutDownHelper=new QSignalMapper; + shutDownHelper->setMapping(this,0); + connect(this, SIGNAL(started()), this, SLOT(setReadyStatus() ), Qt::DirectConnection); + connect(this, SIGNAL(aboutToStop()), shutDownHelper, SLOT(map()) ); +} + +//------------------------------------------------------ +Thread::~Thread() +{ + delete shutDownHelper; +} + +//------------------------------------------------------ +// starts thread, moves worker to this thread and blocks +void Thread::launchWorker(QObject *worker) +{ + worker = worker; + start(); + int i=0; + worker->moveToThread(this); + shutDownHelper->moveToThread(this); + connect(shutDownHelper, SIGNAL(mapped(int) ), this, SLOT(stopExecutor()), Qt::DirectConnection ); + mutex.lock(); + waitCondition.wait(&mutex); +} + +//------------------------------------------------------ +// puts a command to stop processing in the event queue of worker thread +void Thread::stop() +{ + emit aboutToStop(); +} + +//------------------------------------------------------ + +// methods above this line should be called in gui thread context +// methods below this line are private and will be run in secondary thread context + +//------------------------------------------------------ +void Thread::stopExecutor() //secondary thread context +{ + exit(); +} + +//------------------------------------------------------ +void Thread::setReadyStatus() +{ + waitCondition.wakeAll(); +} diff --git a/examples/tutorials/threads/movedobject/thread.h b/examples/tutorials/threads/movedobject/thread.h new file mode 100644 index 0000000..e941e99 --- /dev/null +++ b/examples/tutorials/threads/movedobject/thread.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples 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 Nokia Corporation 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$ +** +****************************************************************************/ + + +#ifndef THREAD_H +#define THREAD_H + +#include + +class Thread :public QThread +{ + Q_OBJECT +public: + Thread( QObject *parent=0); + ~Thread(); + void stop(); + void launchWorker(QObject *worker); +private: + QObject *worker; + QSignalMapper *shutDownHelper; + QWaitCondition waitCondition; + QMutex mutex; +private slots: + void stopExecutor(); + void setReadyStatus(); +signals: + void aboutToStop(); +}; + +#endif // THREAD_H diff --git a/examples/tutorials/threads/movedobject/workerobject.cpp b/examples/tutorials/threads/movedobject/workerobject.cpp new file mode 100644 index 0000000..819da20 --- /dev/null +++ b/examples/tutorials/threads/movedobject/workerobject.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples 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 Nokia Corporation 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 +#include "workerobject.h" + +/* + * represents an object that lives in another thread where it polls a resource + * and communicates with the gui thread + */ + +WorkerObject::WorkerObject(QObject *parent) + : QObject(parent) +{ + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(poll())); +} + +//--------------------------------------------------------------- +void WorkerObject::doWork() +{ + + qDebug() << "doing work in thread " << thread()->currentThreadId() ; +} + +//--------------------------------------------------------------- +WorkerObject::~WorkerObject() +{ + qDebug() << "destruction WorkerObject in thread " << thread()->currentThreadId(); +} + +//--------------------------------------------------------------- +void WorkerObject::startPolling(int milliseconds) +{ + count=0; + timer->start(milliseconds); +} + +//--------------------------------------------------------------- +void WorkerObject::stopPolling() +{ + timer->stop(); +} + +//--------------------------------------------------------------- +void WorkerObject::poll() +{ + qDebug() << QString("timer hit %1").arg(count); + count++; +} + diff --git a/examples/tutorials/threads/movedobject/workerobject.h b/examples/tutorials/threads/movedobject/workerobject.h new file mode 100644 index 0000000..09a827c --- /dev/null +++ b/examples/tutorials/threads/movedobject/workerobject.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples 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 Nokia Corporation 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$ +** +****************************************************************************/ + + +#ifndef WORKEROBJECT_H +#define WORKEROBJECT_H + +#include + +class WorkerObject : public QObject +{ + Q_OBJECT +public: + explicit WorkerObject(QObject *parent = 0); + ~WorkerObject(); +public slots: + void doWork(); + void startPolling(int milliseconds); + void stopPolling(); +private slots: + void poll(); +private: + QTimer *timer; + int count; +}; + +#endif // WORKEROBJECT_H diff --git a/examples/tutorials/threads/threads.pro b/examples/tutorials/threads/threads.pro new file mode 100644 index 0000000..d737513 --- /dev/null +++ b/examples/tutorials/threads/threads.pro @@ -0,0 +1,8 @@ +TEMPLATE = subdirs + +SUBDIRS = hellothread \ + hellothreadpool \ + helloconcurrent \ + clock \ + movedobject + diff --git a/examples/tutorials/tutorials.pro b/examples/tutorials/tutorials.pro index 34723c2..1b4667e 100644 --- a/examples/tutorials/tutorials.pro +++ b/examples/tutorials/tutorials.pro @@ -1,7 +1,8 @@ TEMPLATE = subdirs SUBDIRS = \ addressbook \ - modelview + modelview \ + threads # install -- cgit v0.12