This is the first post using a format that I have been wanting to try out for a long time. The idea is to catalog the questions that might be asked when first learning about a topic. By reviewing these questions, hopefully newcomers can learn a great deal and the more experienced can brush up a bit. The goal is not to exhaustively review every detail on the topic but rather provide just enough information to be dangerous.
For this drilldown, let’s take a look at an important aspect of operating systems: processes and threads.
- What is a process?
A process is an instance of a software program in main memory which is able to be run by the operating system. Processes are essentially isolated environments which contain all of the code and data necessary for the system to execute the program.
- How are processes created?
Processes are created via system calls from other processes. When the operating system is started, a top-level process is created. All other processes are descendants (either directly or through lineage) of this top-level process.
- Is the operating system a process?
The operating system kernel itself is not a process. The kernel is the main operating system logic which (among other things) is responsible for running processes. The kernel is loaded into a special region of main memory (called the kernel space) at startup.
- How are processes run?
Processes consist of one or more threads of execution. If a process has multiple threads, they all share the resources (code, data) provided in the isolated environment. A thread is essentially the information associated with the execution state of a program. The kernel scheduler allocates a slice of time for a thread to execute on a CPU core. The previously executing thread state is saved and the new thread is loaded; this is called a context switch. The old and new threads could be in the same process (a thread switch) or in separate processes (a process switch). The difference between the two switches is that a process switch requires additional work to change between the isolated environments specific to each process.
- What triggers a thread/process context switch?
There are two basic types of switches: voluntary and involuntary. Before the execution of a thread is started or resumed, the kernel scheduler prepares a timer interrupt to occur once the thread’s execution time slice has elapsed. Voluntary switches typically occur when a thread makes a system call requesting access to a resource that is currently unavailable; in this case, the kernel will stop the thread’s execution early. Involuntary switches occur when the thread’s time slice elapses and the interrupt is handled; this technique is called pre-emption.
- How are processes isolated?
Processes are isolated through a main memory management technique called virtual memory. This allows each process to appear as if it has full access to the entire system address space. However, the virtual memory is actually composed of groups called pages which can be mapped to main memory or stored to disk when not immediately needed.
- Can processes communicate to each other?
Yes, the operating system typically provides various inter-process communication (IPC) methods such as shared memory, queues, sockets, pipes, files, etc.
- What are CPU cores?
In simplest terms, a core is the hardware required to execute a thread. For each instruction in a thread, the core must perform several actions such as fetching the instruction from main memory, decoding the instruction, executing the instruction (using hardware called execution units), and finally storing any results. Cores are typically organized to allow each of these actions to occur in separate stages. For example, the fetching of the next instruction will start immediately as the previous instruction moves on to decoding. This effectively allows multiple instructions to be executed in quick succession which increases the core’s throughput. This technique is called pipelining. Some CPUs have multiple cores allowing for simultaneous execution of multiple threads.
- Can one core only execute one thread at a time?
It depends on the core. The most basic core is only capable of executing a single thread at once. Some cores have hardware which increases the number of instructions that can be acted upon at each pipeline stage, increasing the core throughput for that single thread. This type of core is called a superscalar. Techniques which allow multiple threads to execute per core are generally referred to as simultaneous multi-threading (SMT, sometimes referred to as hardware threading). For example, Intel’s Hyper-Threading is an SMT technology which essentially provides a core with two pipelines sharing a single set of execution units. This allows a single core to execute two separate threads.
- How do the terms concurrent and parallel relate?
Concurrency is multi-tasking however each task is not necessarily being performed at the exact same time. For example, a single core non-SMT CPU relies upon the kernel scheduler to juggle running threads; by rapidly switching between threads and allowing each a time slice to execute on the core, concurrency is achieved. Parallelism is multi-tasking where multiple tasks are being performed at the exact same time. For example, a two-core non-SMT CPU can execute two threads at once.
- What are lightweight threads (green threads/greenlets/coroutines/etc)?
These are software techniques that provide concurrency within a single thread. So rather than spawning multiple threads, tasks can be divided up into lightweight threads which execute a portion of their work and then yields execution to other tasks. This loop of executing then yielding continues until the tasks are complete. The kernel scheduler is not involved with the scheduling of the individual lightweight threads within the context of the host thread.
- What is thread safety?
If a process spawns multiple threads, it is possible for those threads to execute the same code. Thread safe code will behave correctly and without problematic side effects when multiple threads execute it.
A process is an isolated environment in main memory used to execute a software program.
A process has at least one thread although more can be spawned.
A thread is information associated with the execution state of a program.
Processes are isolated from one another using virtual memory.
Threads in the same process can share data and code while threads in different processes cannot.
IPC methods are provided by the operating system.
The operating system is responsible for scheduling threads to be executed on a CPU core.
A context switch is when the operating system changes the currently executing thread on a CPU core.
If context switch threads are in different processes, more work is required during the switch.
Each CPU core can execute at least one thread.
CPU cores use instruction pipelining to increase the execution throughput for a thread.
CPU cores with SMT technology can execute more than one thread.
Concurrency is multi-tasking but each task (e.g. thread) is not necessarily being performed at the exact same time.
Parallelism is multi-tasking but multiple tasks (e.g. threads) are being performed at the exact same time.
Lightweight threads provide concurrency within a single thread.
Thread safe code will behave correctly when executed by multiple threads.
I reviewed quite a bit of material while preparing this post. The following is a portion of the resources used and may make for good further reading:
While I have tried to keep terms consistent through this post, please note that some people may use terms differently.