Threads are lightweight processes, that share the same address space; thus they share the same heap but each thread has its own stack.
In a single processor, multithreaded process; switching between threads requires context-switching, to unload the previous TCB and load the new TCB (Thread Control Block) into the CPU; however, this is different from process context-switching that it does not require page switch, since the two threads share the same address space.
Why do you need threads:
Parallelism: threads work in parallel, as each run on a different core (CPU).
Avoid blocking by I/O: if one thread is blocked by I/O, the other threads can continue to run instead of suspending the whole process until the I/O is done.
Creating a thread is like making a function call, but instead of executing the function first and then returning the result to the caller; a new execution thread will be created where it runs independently from the caller, and the schedular decides when to run it.
Critical section. a piece of code that accesses a shared resource, and must be executed by only one thread at a time (no concurrent executions are allowed).
Mutual exclusion. a property that ensures that only one thread can execute a critical section at a time, others must be locked.
Atomicity. is a property for a group of instructions that must be executed as a single unit, without interruption; the hardware guarantee that these instructions are executed fully, or not at all. Similar to the transaction in a database.
Synchronization primitives. are the tools that are used to implement mutual exclusion and atomicity. With the help of hardware and OS, we can implement multithreaded code that accesses critical sections in a synchronized and controlled manner.
#include<pthread.h>intpthread_create(pthread_t*thread,// 1. pointer to a thread (type pthread_t), this is the thread location within the processconstpthread_attr_t*attr,// 2. thread attributes, like stack size, scheduling priority, call `pthread_attr_init()` to initialize a new attributevoid*(*start_routine)(void*),// 3. a function reference (pointer) that will be executed by the thread; entry point of the threadvoid*arg// 4. argument to be passes to 3., must match the function signature of 3.);
Waiting for a thread to finish pthread join((pthread_t thread, void **value_ptr), where the second argument is a pointer to a pointer that will hold the return value of the thread.
Arpaci-Dusseau, R. H., & Arpaci-Dusseau, A. C. (2018). Operating systems: three easy pieces (1.01 ed.). Arpaci-Dusseau Books. https://pages.cs.wisc.edu/~remzi/OSTEP/