[Operating System] Processes and Threads


  • What is a Process?

A process is a program in execution with its associated data and execution context. It's not the same as program or application, which may be running zero, one, or multiple times. Each instance of a running program is a separate process with its own address space and other context.

When a program is compiled into an executable, the executable lives in secondary memory (hard disk). When the operating system runs the executable, it creates a process, which is essentially a data structure containing information about the program, in the main memory (RAM).

A process has the following attributes:

    • Process id.
    • Program counter.
    • Process state.
    • Priority.
    • General purpose registers.
    • List of open files.
    • List of open devices.
    • Protection.
All of these attributes are stored in a process control block (PCB). The PCBs of all processes are chained in a linked list. So by looking at this list, we can know the information of all executing processes.



  • What is in a Process?

Processes live in address spaces that contain the following:
    • Code: the code the program executes.
    • Data: static data such as global variables.
    • Heap: dynamically allocated memory. When you do malloc/free or new/delete, you're manipulating the heap memory.
    • Stack: temporary data such as function arguments, return addresses and local variables.

  • Parents and Children, PIDs
A Unix process comes into being when another process creates it. The new process is the child. The process that created the child is the parent. Every process has exactly one parent. The first process (init/systemd) is created by the kernel during boot.

Every process has a unique process ID number (PID). Internally, the OS has a table of process contexts. The PID is simply an index into that table.


  • Creating a Process: fork()
The fork() system call creates a new process. The child process is an exact clone of the parent process with its own copy of the parent's address space. The child starts running as soon as fork() returns, and both the parent and the child will run simultaneously. Also, parent and child share the same resources (open files, etc).

fork() returns 0 to the child and the PID of the child to the parent, so we can tell the child from the parent and program them to behave differently.


  • Waiting for Child Termination: wait()
Once a program is terminated, the kernel releases any resource it has acquired (allocated memory is freed, open files are closed, etc). However, the process control block (PCB) is not released immediately, because it contains information which the parent might be interested in, e.g. child's exit code. During this time, the child process is called a "zombie".

A zombie process' PCB is freed once the parent calls wait().

wait() is a system call that blocks the parent process until a child terminates. It returns the PID and the exit code of the child. 


  • Pipes
A pipe is a one way FIFO channel. Pipes can be created using the pipe() system call. A pipe has two ends: a write end and a read end. If data is written to the write end, it becomes available for reading on the read end.

We can use pipes for inter-process communication (IPC). The parent process can create a pipe before fork(). The child will inherit both ends of the pipe. The parent can close its unused end and the child closes the other end. The result is a synchronous one way communication channel.


  • Context Switch
Modern computers don't let every process run from its start all the way to its end. Instead, multiple processes are interleaved together. Every process gets to run for a bit of time, and then the kernel stops it and switches to another process. The short-term scheduler picks a process from all ready processes and passes it to the CPU.

Later the CPU will resume to the place where it was stopped. This makes the OS more efficient, because if a process becomes unrunnable, such as waiting for an I/O or synchronization operation to complete, the scheduler may switch out processes that are runnable.

Context switching between processes is quite expensive, as the kernel needs to do a lot of save and load operations, and it doesn't do any other useful work during context switching.


  • Threads vs. Processes
Thread refers to a thread of execution of a process. It contains important information about that process such as program counter, registers, and stack pointers. A process can have multiple threads. The threads share the same address space, but have different stacks and contexts.

These properties give threads several advantages over processes:
  • Creating a thread is cheaper than creating an entire process.
  • Context switching between threads within a process is much cheaper than between processes.
  • Threads within the same process can easily communicate because they share the same memory, whereas processes must communicate through IPC.
The cost of these nice properties is that threads also have some disadvantages. For example, threads of a process share the same protection domain. If one thread runs amok, the entire process can crash. Another big disadvantage is, of course, race conditions.

Comments

Popular posts from this blog

[LeetCode] 631. Design Excel Sum Formula

[LeetCode] 714. Best Time to Buy and Sell Stock with Transaction Fee

[LeetCode] 269. Alien Dictionary