Problems with Processes
Possible scenarios
- A server with many clients
- A computer with many CPU cores
Problems with Processes
Process creation is heavyweight
- Space must be allocated for the new process
- fork() copies all state of the parent
IPC (Inter Process Communication) is cumbersome
- Each message have to go through the kernel
Each process has independent address space
⇒ Doesn't share memory
⇒ Different processes can't point the same address space
Threads
Threads
Light-weight processes that share the same memory(= address space)
Every process has at least one thread
Benefits
- Resource sharing, no need for IPC
- Faster to create, context switch
- Context switch between the different threads within a process
doesn't change the address space, but the IP, Stack, Reg vals
- Simple to use the multi-core CPU

- Registers and Stack is context, so they are required for each thread
Thread implementations
1. User threads
- User level library manages threads
- POSIX Pthreads, Windows threads, Java threads
2. Kernel threads
Multithreading models
Many to One
- Many user level threads mapped to single kernel thread
- One thread blocking causes all to block
- e.g.) User thread request I/O
→ From the OS's view, the kernel requested I/O
→ Send the kernel thread to wait Queue
→ Other user threads can't run
- Multiple threads may not run in parallel on multicore
because only one may be in kernel at a time
One to One
- Each user level thread maps to kernel thread
- Creating a user level thread creates a kernel thread

Many to Many
- Many user level threads map to many kernel threads
- # kernel threads ≤ # user threads
- Not to be One to One, so can save kernel resource

Two level model
- Similar to M:M, allows a user thread to be bound to kernel thread

POSIX Pthreads
Specification, not implementation
Implementation is system dependent
- On some platforms, user level threads
- On others, maps to kernel level threads
Pthread API
pthread_attr_init()
- initialize the threading library
pthread_create()
- create a new thread
- get the code to be executed as an argument (runner in the above fig)
pthread_exit()
pthread_join()
- wait for another thread to exit
Linux Threads
How to create new threads
New threads created using the clone() API
- Create a new child task that copies the address space of the parent
- Same code, same env
- New stack is allocated
- No memory needs to be copied (unlike fork())
Thread oddities
What happens if you fork() a process that has multiple threads
- Get a child process with exactly one thread (called fork())
What happens if you run exec() in a multiple threaded process
- All but one threads are killed
- exec() change the program(= code data) being run by the current process
→ previous threads can't be runned
Advanced Threading
Thread pools
- Create many threads in advance
- Dynamically give work to threads from the pool
Advantages
- Cost of creating threads is handled up-front
- Bounds the maximum number of threads in the process
TLS: Thread Local Storage
- Not global to all threads
- Not local storage on the stack
Each thread can have its own space for "global" variables
Similar to static variables
OpenMP
- Compiler extensions for C, C++ for parallel programming
Process vs Threads
Threads are better if
- Need to create new ones quickly
- Need to share lots of state
Processes are better if
- Need protection
- One process that crashes doesn't impact the others
- Need high security