Getting the computer to manage several tasks seemingly simultaneously is the heart of multitasking. You can choose to write tasks separately as though nothing else ever happens—separate modules. The ideas involved are not difficult to visualize if you compare them with everyday activities, but they differ from those of normal programming. You should develop the frame of mind that says, “If it isn’t ready yet, go on. I’ll come back to it later. Right now there may be something else to do.” Tasks may be inter-related; then you will have to plan signaling between them. Once you’ve understood the ideas of this section, it will be easy to move to complicated systems involving many calls with many parameters. Realtime systems are becoming increasingly important as the dedicated microcontroller becomes more and more prevalent. Knowing the concepts, you can have a role in the implementation. Several different approaches to multitasking are described next.
Cooperative multitasking–Round Robin
If priority is not important, no special hardware is needed for a cooperative multitasking scheme where each task politely pauses at frequent points to “go to the end of the line” or “wait ‘till the next time around” and allow other tasks to get a chance to do some work. The weakness is that if some task gets added that doesn’t cooperate, there is no protection in the operating system and all the other tasks can be blocked. This might better be called “multiple tasking.” It is a round-robin system where tasks run one after the other in turn, without the idea of preemption or priority that are essential for external realtime events. Although this approach can include interrupt service routines, attention is centered on what really should be called the background tasks. In such a scheme each task waits its turn to run. If a task has nothing to do at the time, it immediately passes control to the next task, but if it has a lot to do, it can spend all the time it needs to finish. Such a system avoids the overhead of an operating system, but requires the programmer’s close attention to avoid long latency (delay in getting back around the loop to the task needing attention). You have to be sure to break big tasks into several small tasks or scatter around intermediate pauses to be sure the running task doesn’t hog the processor.
Time slice
The time slice multitasking approach addresses some of these problems. It provides protection from hogging the processor by arbitrarily switching out long-running tasks at regular intervals. With this approach, tasks usually run round-robin unless a task takes more than an allotted amount of time. At that point the task is put on the shelf and the next task in line gets to run. The first task goes to the end of the line and is allowed to continue running when its turn comes around again. There must be a timer-driven interrupt marking off time slices so control of timing is removed from the running task. This approach is good for data processing applications and was the heart of early time-shared computing systems, before the personal computer revolution. In its basic form, though, it doesn’t allow the feature of preemption needed for non-deterministic systems—ones where urgent tasks may unexpectedly or unpredictably need immediate attention.
Scheduler
A scheduler is somewhat related to a time-slice system in that it keeps track of time for the various tasks. Typically, however, there are some tasks that are short and repetitive, such as scanning external inputs or sending regular outputs. These short tasks may come frequently or only occasionally and at irregular intervals. Any left-over processor time is used for a background task, which is often a much less urgent data-processing or decision-making activity.
Priority-based, preemptive multitasking
There are a confusing number of combinations of these types of multitasking when you begin to add in priority of tasks. More urgent tasks can go to the head of the line or preempt the running task. A common combination is a priority-based, preemptive multitasking operating system where equal priority tasks run in round-robin fashion and the system switches tasks based on both timer events and external hardware events. These events may be periodic events like the ticks of a clock for a scheduler, or dynamically changing events based on inputs from outside hardware. An event is anything that might cause the system to change tasks. It could be an external interrupt, an internal signal or message sent from another task, or the expiration of a waiting period. The primary point is, events can lead to a change in which task is running.