Symbian and Qt both provide typical multitasking functionality in the form of threads, processes, synchronization and inter-thread communication. The Qt Mobility API provides limited access to Symbian's inter-process communication API but otherwise the two approaches are separate. Both also provide different in-thread cooperative multitasking systems.
Multitasking is the ability to perform more than one task at a time. It is important to GUI applications, because it allows them to perform long running or computationally expensive operations while still remaining responsive to user input.
There are two types of multitasking: preemptive and cooperative. In preemptive multitasking (or "multithreading"), the operating system gives each thread of execution some time in which to run - the thread has no control over when it runs or how much time it gets. In cooperative multitasking, a scheduler controls which task is run next, but the current task alone determines when it completes.
Preemptive multitasking is heavier-weight in terms of RAM and execution speed, and is more difficult to program because of the need to mediate access to shared resources (and ensure threads do not dead-lock). Cooperative multitasking is easier - because access to resources is serialized. However individual tasks need to be short running so that the UI remains responsive.
In multitasking operating systems we use the term process to refer to a set of threads that share the same global memory space, and which can therefore directly access each other's variables. All the threads in an application typically run in the same process. However, it is threads, not processes, that are scheduled for execution.
A multitasking operating system may also be multiprocessing. Multiprocessing is where threads can run on more than one processor (CPU).
The Symbian platform is a modern preemptive multitasking operating system.
Applications are created in their own process, running in a single main thread. The kernel preemptively schedules all threads in the system, based on their priority. Although it is possible to create secondary threads, Symbian strongly encourages applications to cooperatively multitask using active objects.
Almost all Symbian services are provided by
servers (or "daemons") running in other processes (for example, the
File Server, Window Server, Font and Bitmap Server, and Location Server).
These usually export an asynchronous API that takes a reference to
a TRequestStatus
object that the server uses to signal
completion of the request. Active objects provide a consistent and
lightweight way to write code to submit the asynchronous requests
and handle their completion.
Active objects are derived from CActive
, which either owns or has a handle to an asynchronous
server provider. The active object must add the object to the active
scheduler in its constructor and provide a method to set itself as
active - first calling the asynchronous method (passing in theTRequestStatus iStatus
member) and then calling CActive::SetActive()
. When the asynchronous service completes,
it signals the active object's thread semaphore and changes the status
of the object's iStatus
to show that it is no longer
pending. The active scheduler later calls the object's RunL()
method, which you must implement, to handle completion of the service.
Note that this is not immediate - active objects are cooperatively
multitasked so the scheduler can only run one at a time, and only
when the last one has completed. Lastly, you must implement the virtual DoCancel()
which cancels the asynchronous request, and ensure
that you call Cancel()
in the active object's destructor.
The above summary only touches on the nuances possible with active objects. If you're interested in using or implementing services you may also be interested in reading the Client/Server Overview.
Developers that prefer to use threads and processes can
of course do so - in some cases this may be necessary. Symbian C++
processes and threads can be created and manipulated using the RProcess
and RThread
API, respectively.
Symbian C++ has the usual synchronization primitives including mutexes
(RMutex
), semaphores (RSemaphore
), Critical Sections (RCriticalSection
) etc. All
of these classes are discussed in Thread And Process
Management and Inter Process Communication.
Threads in the same process can easily share data directly (taking care to serialize access to shared data). Threads in other processes need to communicate using Symbian's inter-process communications mechanisms. These include Client/Server, Publish and Subscribe, and Message Queues.
Symbian adds support for symmetric multiprocessing (SMP) from Symbian Anna.
The Qt Mobility API provides access to Symbian's Publish and Subscribe API.
Qt applications use both cooperative and preemptive multitasking.
Qt's main application thread runs its own event loop which processes events generated in response to user interaction (key presses, mouse events etc) and from timers and the window system. This event loop is an example of cooperative multitasking - events are queued and handled synchronously. If too much time is spent on one event then the UI can become unresponsive.
If the computationally
intensive operation can be broken into a number of steps - for example
writing to a file, then you can call QApplication::processEvents()
at regular intervals during the operation to give the event loop
time to handle other events from the UI. This approach is discussed
in chapter 7 of C++ GUI Programming with Qt 4 , Second Edition,
Jasmin Blanchette and Mark Summerfield, Prentice Hall (2006) (the first edition is available free online here).
Some Qt APIs, particularly those for networking, have blocking and non-blocking APIs, making it possible to choose between synchronous and asynchronous styles of programming. The non-blocking APIs provide the ability for the developer to call a method, return control to the event loop, and at a later time receive the result of the call in the form of a signal.
Multithreading (preemptive multitasking) offers an alternative approach. The QtConcurrent classes provide the ability to define concurrent functionality without having to write the thread-management code. The QtConcurrent system then handles the thread creation and synchronization and scales the number of threads as appropriate.
For cases where QtConcurrent is not appropriate, low-level thread
management is possible by developers subclassing QThread
and re-implementing its run()
function to execute
code in the new thread. Synchronization classes include QMutex
to provide mutually exclusive access to a resource, QReadWriteLock
which provides unrestricted access for reading but blocks on writing, QSemaphore
which generalises QMutex to allow access to a
specified number of resources, and QWaitCondition
which blocks until some condition comes true. There are also a few
helper classes like QMutexLocker
, which simplify
mixing mutex programming and standard C++ exception handling.
There are a few good examples here: Mandelbrot Example, Semaphores Example, and Wait Conditions Example. C++ GUI Programming with Qt 4 , Second Edition, Jasmin Blanchette and Mark Summerfield, Prentice Hall (2006) contains an excellent discussion of the multithreading (with some duplication of the other links) in chapter 14.
Threads communicate with each other using shared memory and the above synchronization classes. Threads communicate with the main thread using signals and slots. Note however that by default the signals are not synchronous as they are within a single thread.
Applications can also multitask using other processes. For example
it is possible to create a QProcess
to launch another
process, set its command line arguments and to detect its startup,
error and completion status.
You can also use standard C++ threads, processes and inter-process communication mechanisms.
Most of the material in this topic is based with permission on a Symbian Foundation wiki article Apps:Using Qt and Symbian C++ Together . The version used was that available at Symbian Foundation on 3 November 2010. The content in this page is licensed under the Creative Commons Attribution-Share Alike 2.0 UK: England & Wales License (http://creativecommons.org/licenses/by-sa/2.0/uk).