standard for programmable microcontrollers, including almost any computer-based controllers, such as single board computers, numerical, and event-based controllers. There are several different types of software architecture in common use today. Simple control loop In this design, the software simply has a loop which monitors the input devices. The loop calls subroutines, each of which manages a part of the hardware or software. Hence it is called a simple control loop or programmed input-output. Interrupt-controlled system Some embedded systems are predominantly controlled by interrupts. This means that tasks performed by the system are triggered by different kinds of events; an interrupt could be generated, for example, by a timer at a predefined interval, or by a serial port controller receiving data. This architecture is used if event handlers need low latency, and the event handlers are short and simple. These systems run a simple task in a main loop also, but this task is not very sensitive to unexpected delays. Sometimes the interrupt handler will add longer tasks to a queue structure. Later, after the interrupt handler has finished, these tasks are executed by the main loop. This method brings the system close to a multitasking kernel with discrete processes. Cooperative multitasking Cooperative multitasking is very similar to the simple control loop scheme, except that the loop is hidden in an API. The programmer defines a series of tasks, and each task gets its own environment to run in. When a task is idle, it calls an idle routine which passes control to another task. The advantages and disadvantages are similar to that of the control loop, except that adding new software is easier, by simply writing a new task, or adding to the queue. Preemptive multitasking or multi-threading In this type of system, a low-level piece of code switches between tasks or threads based on a timer invoking an interrupt. This is the level at which the system is generally considered to have an operating system kernel. Depending on how much functionality is required, it introduces more or less of the complexities of managing multiple tasks running conceptually in parallel. As any code can potentially damage the data of another task (except in systems using a memory management unit) programs must be carefully designed and tested, and access to shared data must be controlled by some synchronization strategy such as message queues, semaphores or a non-blocking synchronization scheme. Because of