LOADING

加载过慢请开启缓存,浏览器默认开启

COMP310_multithreading

Multithreading

Purpose

Still use web server as an example:

  1. 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
  2. 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

  1. Divide “work” among multiple threads(based on the property of work per se)
  2. Shared data
    • Only global variables and heap can be shared.
    • shared data accession by critical section

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
    }
}

htop can 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:

  1. Fine-grain locking:
    • Multiple locks on individual pieces of shared data
  2. 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:

  1. No production when N are all full(harder to deal since info may loss)
  2. No consumption when no entry is full(easy to deal)
  3. 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
Multiple producers and consumers