Continuing from part 2, let’s start this article with a bit of context first (and if you don’t like reading text, you can skip this introduction, and go directly to the section below where I discuss pieces of code).
When we start an application program, the operating system creates a process.
Each process has a unique id (we call it a PID) and a memory boundary.
A process allocates its required memory from the main memory, and it manipulates data within a boundary.
No other process can access the allocated memory that is already acquired by a process.
It works like a sandbox, and in that way, avoids processes stepping on one another’s feet.
Ideally, we can have many small processes to run multiple things simultaneously on our computers and let the operating system’s scheduler schedule them as it sees fit.
In fact, this is how it was done before the development of threads. However, when we want to do large pieces of work, breaking them into smaller pieces, we need to accumulate them once they are finished.
And not all tiny pieces can be independent, some of them must rely on each other, so we need to share information amongst them.
To do that, we use inter-process communication. The problem with this idea is that having too many processes on a computer and then communicating with each other isn’t cheap. And precisely that is where the notion of threads comes into the picture.
The idea of the thread is that a process can have many tiny processes within itself. These small processes can share the memory space that a process acquires. These little processes are called “threads.” So the bottom line is that threads are independent execution environments in the CPU and share the same memory space. That allows them faster memory access and better performance.