First, let’s introduce a new abstraction as thread. Instead of viewing the execution within a program from a single point, a multi-threaded program has more than one point of execution. Each thread is like a separate process except that they share the same address space and can access the same data. Threads separate streams of executions that share an address space.
Doing context switch for thread is similar for context switch in process, except that we use thread control blocks(TCSs) instead of PCB and the address space is not switched.
Also, in multi-thread processes, each thread runs independently thus in the address space of such process, there will be more stacks and register group inside the space called thread-local storage, one allocated for each thread.
Why use threads if they can introduce more problems and brings in harder concepts? By using threads, we can achieve:
Thread creation is a bit like making a function call, but instead of executing the function and return to caller, the system creates a new thread of execution for the routine that is being called and it runs independently of the caller(runtime is determined by the OS scheduler).
Race Condition: exist when multithreaded (or otherwise parallel) code that would access a shared resource could do so in such a way as to cause unexpected results.
How to solve it? By mutual exclusion, that is, when one thread is executing within the critical section(the shared data), the others will be prevented from doing so.
Atomicity: an instruction is atomic if it’s “all or nothing”, so it can either execute fully or not executed at all and there’s no “half-way”, can’t be interrupted.
One approach to solve the problem is by achieving atomicity for each instruction involving the critical section. And to do so, we want to ask the hardware for a few useful instructions upon which we can build a general set of synchronization primitives. And that’s the main idea of the concurrency chapter.
imagine some code is depend on some earlier code but two threads are looking at the two codes at the same time. Now one thread must wait for another to complete before it continues.