What is the difference between Multiprogramming and Multitasking
They are more or less synonymous. Multiprogramming is more used when one CPU is involved, that is being switched from a process to the other, processes which are residing in memory simultaneously. Along came threads, and it wasn't switching between programs anymore...
Processors, particularly the intel line, had the mechanisms for true multitasking (timer interrupt, privileged instructions) since at least the 80286. The M68000 used in the very first Mac was a processor with full-fledged multitaking capacities. This isn't a recent development in architectures. Note that the very first time shared systems swapped the user's programs in and out, and thus weren't really multiprogramming in the sense of having several programs in memory at the same time.
The idea is to have several programs residing in memory simultaneously, so that when one yields the CPU (by finishing or by waiting) there are others ready to use the CPU, thus increasing CPU utilization (and as you can consider each CPU burst to be preparing for a use of I/O, increase overall usage). This gives better thoughput (important in batch systems).
Along came time sharing, several interactive users connected to the machine. Same idea, keep their programs around but switch among them fast enough so they have the ilusion of &quot;having a computer to themselves&quot;. Requires a timer that interrupts the CPU to avoid monopolization.
On personal machines there was not much incentive to run several programs at a time, at least initially (one user in front of a severely limited machive didn't expect much). As machines grew, a way of working around this and allowing several programs at a time without changing the operating system much was &quot;cooperative multitasking&quot;, in that every program is suposed to yield periodically to the operating system to select another one to run. As the program doing this is in full control, it can select to do this when nothing could get messed up by others. Needless to say, a program &quot;forgetting&quot; to fullfil its duty to yield gets an interesting boost in performance... early Mac systems worked this way, and for the above reasons this didn't last too long. On embedded systems with no or only rudimentary operating system, and a tightly controlled set of programs running, this is certainly an attactive option.