Various processes running in the same computer implies a risk of having one process corrupting some other process memory, because of that; memory protection concept evolved into the allocation of distinct pages of memory for each process into segments, its limitations are defined by two hardware registers, hence, if a process tries to access memory outside the defined segment a protection mechanism is used, such as Intel's general protection faults. Having that; the concept of memory management unit (MMU) appeared as the set of components responsible for handling memory access from the CPU.
Time-sharing has also had a very interesting evolution into what we know as multitasking, which defines scheduling policies that decide which task runs at any given time, and establishes a mechanism known as context switching that reassigns CPU from one process to another. Concept began at computing early days, where peripherals (devices hooked up to the CPU) became much more slower than processing units, so when a process needed access to a peripheral, the CPU had to stop executing instructions while such peripherals were busy. Thus, multiprogramming idea came to scene by context switching every time a process was waiting, but that gave no guarantee of process to be run at proper times, since one could run for very long periods of time without triggering a context switch. That was absolutely not suitable for interactive computing needs, therefore cooperative multitasking was designed; there, processes ceded time to each other in a voluntary manner, however multitasking dangerously relied on each process to efficiently give time to the others, consequently the preemptive multitasking idea was born about assigning operating time slices to each process. Only then; processes were cataloged into two different groups; CPU-bounded ones as those who were fully utilizing CPU, and I/O bound processes as those waiting for input or output from peripherals. A perfect Martini came out of blending preemptive multitasking with hardware interrupts, which would rather than inefficient I/O bound process to constantly check for resource availability. It gives a call to subroutines handling the interrupt event of resource availability, changing I/O bound processes state from on hold or blocked to unblocked as it may correspond, meaning that blocked processes would properly return to execution.
At that point processes were so handy, that programmers started use them by assigning different tasks to different processes, which then was generally understud as a set of cooperating processes that people started to reffer as applications, the main issue behind it, was finding appropriate ways to exchange information between application's processes. As a result of that search; Threads were proposed as cooperating lightweight processes coexisting in a shared memory space or context, thus, another advantage was found in their favor, and it was that memory context switching was not necessary when context switching between threads.