But of course.Multi-tasking/threading makes it possible to divide a program into individual, relatively independent tasks/threads/parallel processes, depending on the task to be solved. This makes programming much easier, the number of cores does not matter. An example from the field of embedded software (32 bit microcontrollers, 1 core) shows the following tasks:
- cyclic operation of binary I/O via the I2C bus (in a loop for several blocks: trigger transfer, wait for end of transfer)
- Debounce all binary inputs
- cyclic operation of the measurement of ambient noise
- cyclic sending of status messages via the CAN bus
- Command interpreter for commands entering via the CAN bus
- Control of the sound system
In addition, there are the following interrupt routines (ultimately also parallel processes):
- Timer interrupt for the timers of the multi-task kernel
- Timer interrupt for cyclic operation of the CAN bus bridge
- 2 interrupts from the I2C bus controller
- Timer interrupt for signal preprocessing of noise measurement
In principle, all tasks could also be grouped into one thread, which cyclically calls up a number of subprograms: within the subprograms, however, it is not allowed to wait, otherwise the complete processing would be blocked.However, since there are various places in the individual tasks where maintenance has to be carried out (e.g. for receiving a CAN bus message or for the expiry of a period of time), the assigned subprograms would have to be realized in the form of finite state machines. This is possible, but very tedious and laborious in programming. Why do you do this when you can have it much easier?
Perhaps I can put it a little differently:
The most important feature of a multi-task kernel is that it can structure software into parallel processes (tasks).This makes the software understandable and ensures that the system can always react quickly enough to external requirements (by operation or by hardware events). This requires that control can be temporarily passed to the other tasks even within nested subprogram calls. This avoids “busy waiting”, which would temporarily paralyze processing. Strictly speaking, in such a multi-task kernel, the task flow is not parallel, but only quasi-parallel. The individual tasks calculate sequentially only for a short period of time. For the external observer, it looks as if all tasks will work in parallel within a certain amount of time blurring.
Note: the above multi-task kernel for Cortex-M3/M4 (approximately 600 bytes of code) uses cooperative multitasking, which is sufficient here and simplifies programming.