I defined process as an address space with system state / rights, such as I/O descriptors, current directory, user ID, etc, along with at least one thread of control. A thread is a register set, a virtual CPU.
Context switching is when the current CPU registers' values are written (saved) to memory, and the values from the register set of another thread is loaded.
I talked about kernel-level threads and how an operating system kernel will context switch when a thread becomes blocked (e.g., due to an I/O request). I also talked about user-level threads -- or coroutine threads -- which is managed by user-level application code (usually library code); coroutine threads are not known to the OS, so if a coroutine thread makes a blocking system call, the OS can not automatically context switch to another coroutine thread.
When kernel-level threads do not belong to the same process, the OS must change the virtual address to physical address translation, so that the new process can not modify memory that belongs to the old one. This is address space protection -- such a separation of address spaces means that one buggy program can not cause another, unrelated program to crash.
User-level threads are often implemented in a library; kernel-level threads are built into the operating system. In both cases, the context switch operation is typically mediated by assembly language code -- though it is possible to write a portable threads package without resorting to assembly, doing so is a little tricky and can restrict the thread library's interface in undesirable ways.
email@example.com, last updated