Threading
In interactive applications threading is a fundamental feature. All time-consuming tasks should be separated from the main application thread, and executed in background threads. If this is not done, then performing those tasks in the main thread would cause the whole application to halt for the duration of the action, which is generally detrimental to the user experience.
In the world of multitouch interaction "time-consuming" means any action that takes more than 10 milliseconds to carry out. Typical operations that should be threaded are:
- Opening a file
- Reading data from a file
- Writing data to a file
- Using sockets
- Resizing large images
- Decoding videos
- Initializing widgets
This section covers some of the basic techniques related to threading, with problems and solutions.
Caveats
Before starting a single thread one needs to consider the issues that come with threading. The usual problems are:
- Data corrution, when the same data is accessed from multiple threads
- Thread cleanup, when the thread needs to be shut down after being used.
Data corruption is a standard problem that needs to be addressed when-ever threads are used. In C++ (unlike Java or some other languages) there is no built-in protection mechanism that would prevent two threads from accessing the same data structures in a conflicting way.
A practical example is that when new Widgets are loaded in a background thread, they need to be added to the scene. This cannot be done directly from the background thread, since the widget graph might be used by other threads at the same time, and any modification would crash or corrupt the applications. As a solution one needs to put the new widgets to a special container that is protected by mutex locks. An example of this can be found in the TimeLine application, where class MainWidget receives new widgets from the background thread in the function backgroundAddWidget.
BGThread
BGThread is a component that executes tasks in a background thread. Typical examples of the use are file loading, and periodic tasks. In the BGThread model the actions are encapsulated into Task objects, that are executed one after another.
The BGThread approach is useful for operations that might take over 10 milliseconds, but that can be carried out in reasonable amount of time (for example 100 milliseconds). Since the tasks are executed one after another, a single misbehaving Task will block all the others.
The BGThread is often used to make sure that the CPU is not excessively loaded. For example when an application starts there might be hundreds (or thousands) of images to load. If one spanned a thread for each image, the computer would be congested with all the requests. Instead it is better to run the image loading tasks one after another, which will not suffocate the CPU.
With BGThread, each task has a priority and scheduled execution time. The tasks are executed in the priority order, based on the their timing requests. As long as there are high-priority tasks to be handled, the low-priority tasks will be ignored.
Example of BGThread usage can be found in the TimeLine application. In TimeLine the loading of new media is handled in a BGThread Task (class ItemLoader). ItemLoader will check periodically for new media to load, and insert new media into the time-line. ItemLoader will also avoid congesting the BGThread with too many operations, so that other operations can be carried out while the media loading is taking place.
Standard Threads
Ordinary threads (e.g. class Radiant::Thread) are useful in handling tasks that do not fit into the BGThread model.
Practical examples are video decoding and socket transactions. Video decoding is incompatible with BGThread approach, since it is not possible to wait for other tasks to carry out when a video is to be decoded. Video decoding is typically quite heavy, so for performance reasons it is better to span more than one thread for it.
Socket transactions do not fit into the BGThread model, since often a socket read -operation might take arbitrary amount of time, from one microsecond to minutes or hours.
