A Brief Overview of Multithreading
Sep 25, 2023by, Amalendu KR
Modern Computers are capable of completing multiple operations simultaneously as a result of which programs run faster in execution and responsiveness compounded by exponential advancements in hardware and software capabilities over the decades.
To utilize this capability is tricky and requires the programmer to have a deep comprehension of what happens under the computer’s hood.
Properly naming objects: Processes and threads
All Modern OS are capable of running multiple programs at once like running a browser and playing music at the same time. Every running programme is referred to as a process. To successfully achieve this and to make the user feel like they are viewing multiple programs at the same time, modern OS utilize many software tricks as well as the underlying hardware.
There are other ways to run multiple programs at the same time other than using multiple processes. Each process can have its own subtasks within itself called threads. A thread is basically a slice of the process, and each process triggers at least one of the threads upon startup of that program termed the main thread. When the program/user needs/demands more resources more threads are allocated to the process. This is the essence of multithreading: Multiple threads run within a process.
Concurrency vs Parallelism
Concurrency essentially fakes the system into thinking it is running multiple operations at the same time, while in true parallelism tasks literally do indeed run at the same time.
The crux of the issue comes from the fact that a single core in a CPU can only run a single operation at a time. It becomes immediately obvious how single-core systems then have a major disadvantage over multi-core systems.Furthermore, OS has advanced techniques like preemptive multitasking to give the user the ability to run multiple programs at once, essentially interrupting a task, switching to another one and then switching to the previous one as defined by the needs of the user. So this method essentially gives you the illusion that multiple programs are running at once.
For true parallelism to happen multi-cores are essential, true parallelism on a single-core machine is impossible to achieve. In multi-core processors, OS detects the number of cores and assigns processes according to sophisticated scheduling algorithms. Also, preemptive multitasking can still kick in if all the cores are busy. Still, it makes sense to write multithreaded applications for the single-core machine if it can benefit from it using preemptive multitasking.
Things run smoothly as long as threads just read from the same memory spaces, but as soon as threads write to the same pointers issues start to arise, namely: data race and race condition.
- Data race: While a reader and writer thread is working on the same memory the reader might attempt to read from the memory before the writer has finished writing to the memory, leading to the reader reading corrupt data.
- Race condition: When two/more threads run in the wrong order this can lead to unpredictable behavior.
Thread safety is when a piece of code works correctly without data races/race conditions and there are even specific libraries that declare themselves thread-safe so that the code runs smoothly.
Mitigation of race conditions and data race involves concurrency control, where accommodation of two/more concurrent threads is managed by the OS/programming language. Some of the techniques are:
- Synchronization – This method ensures that only one thread at a time uses the resources. Here specific parts of the code are marked as ‘protected’ so that the simultaneous execution of concurrent threads is stopped.
- Atomic operations – Conversion of non-atomic operations to atomic ones using special instructions from the OS. This ensures the shared data is always in a valid state.
- Immutable data — Here the shared data is made immutable, meaning it can’t be changed: only reading is allowed from the shared data thus eliminating the root cause.
So that’s a brief overview of multithreading and concurrency control and it is an important aspect every developer should be aware of.
Disclaimer: The opinions expressed in this article are those of the author(s) and do not necessarily reflect the positions of Dexlock.