Multithreading
Purpose
Still use web server as an example:
- to ensure a certain level of security(for example, to guarantee the running code on the server would not disrupt anything), we may use multiprocess since process itself ensures a segregation
- if security is guaranteed, multithread can be considered to its efficiency(by shared data)
Static data tend to be processed by thread, dynamic by process in server.
Basic Approach to Multithreading
- Divide “work” among multiple threads(based on the property of work per se)
- Shared data
- Only
global variablesandheapcan be shared. - shared data accession by critical section
- Only
Locking
For example, we may want to have a multithreading program compute the sum and products of elements in two arrays:
main(){
int i, sum=0, prod=1
for(i=0;i<MAX_THREADS;i++){Pthread_create(...)}
for(i=0;i<MAX_THREADS;i++){Pthread_join(...)}
printf(sum)
printf(prod)
}
Threadcode(){
int i,c
for(i=my_min;i<my_max;i++){
c = a[i] * b[i]
sum += c
prod *= c
}
}
htopcan be used to check the status of the resources(CPU,memory…)
We need to implement lock in thread to prevent data racing.
The naive way would be to implement biglock:
Threadcode(){
int i,c
for(i=my_min;i<my_max;i++){
c = a[i] * b[i]
pthread_mutex_lock(biglock)
sum += c
prod *= c
pthread_mutex_unlock(biglock)
}
}
However, it reduces performance since single lock inhibits parallelism. Therefore, two approaches invented to deal with it:
- Fine-grain locking:
- Multiple locks on individual pieces of shared data
- Privitization
- Make shared data accesses into private data access
Fine-Grain Locking
Threadcode(){
int i,c
for(i=my_min;i<my_max;i++){
c = a[i] * b[i]
pthread_mutex_lock(sumlock)
sum += c
pthread_mutex_unlock(sumlock)
pthread_mutex_lock(prodlock)
prod *= c
pthread_mutex_unlock(prodlock)
}
}
## 2 lock accesses per thread, per iteration
Privitization
Idea:
For each thread define the local variables to represent the parts of the global variables; access the loop by the locals. Finally using the lock to the local variables.
Threadcode(){
int i,c
local_s =0
local_p =1
for(i=my_min;i<my_max;i++){
c = a[i] * b[i]
local_s += c
local_p *= c
}
pthread_mutex_lock(sumlock)
sum += local_s
pthread_mutex_unlock(sumlock)
pthread_mutex_lock(prodlock)
prod *= local_p
pthread_mutex_unlock(prodlock)
}
## 2 lock accesses per thread, in total
Producer/Consumer Problem
Arises when two or more threads communicate with each other.
Def:
One shared bounded buffer with N entries. Requirements:
- No production when N are all full(harder to deal since info may loss)
- No consumption when no entry is full(easy to deal)
- Access to the buffer is mutually exclusive(at a time only one process should be able to access the shared buffer and make changes to it)
Locks cannot deal with it
Solution: Semaphores
check the lecture
Single producer and consumer
Requires 2 semaphores:
- emptyBuffer: initalize to N -> N empty buffers; producer can run N times first
- fullBuffer: initialize to 0 -> 0 full buffers; consumer can run 0 times first