Synchronization & Deadlock

Part 1: Mutex Locks

Critical Section

When thread process the variable. There are three steps:

  • 1 Copy the variable from memory to CPU
  • 2 Do some calculation
  • 3 Store the new value back to memory

If multiple thread is executing same variable at the same time, there might be a critical section.

mutex_lock

We can use pthread_mutex_lock() to avoid the critical section.

    pthread_mutex_t *lock = malloc(sizeof(pthread_mutex_t);
    pthread_mutex_init(lock,NULL);
    //same as pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER
    pthread_mutex_lock(lock);
    
    pthread_mutex_unlock(lock);
    pthread_mutex_destroy(lock);
    free(lock);
复制代码

Pthread_mutex_lock won't stop other threads, other threads will have to wait when they are trying to lock the same lock until the mutex is unlocked. If a mutex was locked, it can't be unlock by another thread.

Gotchas

  • Multiple threads init/destroy has undefined behavior
  • Destroying a locked mutex has undefined behavior
  • Forgot to unlock will lead to deadlock
  • Can't copy pthread_mutex_t to a new memory location
  • Use uninitialized mutex
  • Not calling destroy lead to resource leak
  • Locking/ unlocking wrong mutex

Part 2: Counting Semaphores

    sem_t s;
    sem_init(&s, 0, 10);
    sem_wait(&s);
    sem_post(&s);
    sem_destroy(&s);
复制代码

Thread Safe Push:

   pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
   int count = 0;
   double values[10];
   sem_t sitems, sremain;
   
   void init(){
        sem_init(&sitems, 0, 0);
        sem_init(&sremains, 0, 10);
    }
    
    double pop(){
        sem_wait(&sitems);
        pthread_mutex_lock(&m);
        double result = values[--count];
        pthread_mutex_unlock(&m);
        sem_post(&sremains);
        return result;
    }
    
    void push(double v){
        sem_wait(&sremains);
        pthread_mutex_lock(&m);
        values[count++] = v;
        pthread_mutex_unlock(&m);
        sem_post(&sitems);
    }
   }
复制代码

Three desired properties for solutions to the critical section problem

  • Mutual Exculsion: Only one thread/process get access
  • Progress: If there is no progress inside critical section, thread should be able to get inside without waiting
  • Bounded: The wait time should be finite

The Critical Section Problem

raise my flag
turn = your_id
wait while your flag is raised and turn is your_id
//Do critical Section
lower my flag
复制代码

Part 3: Condition Variables

What is condition variable

It allow threads sleep until tickled. We can use pthread_cond_signal() to wake up one thread (System decide which one to wake up) or all threads with pthread_cond_broadcast(). There will be a spurious wake of waiting thread.

  • spurious wake exist for performance.

pthread_cond_wait

  1. unlock the mutex
  2. wait until pthread_cond_signal is called
  3. lock before return

Use condition number to write semaphore

    define struct sem_t{
        int count;
        pthread_mutex_t m;
        pthread_cond_t cv;
    } sem_t
    int sem_init(sem_t *s, int pshared, int value){
        if(pshared){errno = ENOSYS;return -1;}
        s->count = 0;
        pthread_mutex_init(s->&m, NULL);
        pthread_cond_init(s->&cv, NULL);
        return 0;
    }
    void sem_wait(sem_t *s){
        pthread_mutex_lock(s->&m);
        while(s->count == 0){
            pthread_cond_wait(&cv,&m);
        }
        s->count--;
        pthread_mutex_unlock(s->&m);
    }
    void sem_signal(){
        pthread_mutex_lock(s->&m);
        count++;
        pthread_cond_signal(s->&cv);
        pthread_mutex_unlock(s->&m);
    }
    
复制代码

Part 4: Barrier

Barrier is used to wait N threads to reach a certain point before continuing onto next step. There is a function named pthread_barrier_wait(). We need to declare a pthread_barrier_t variable and initialize it with pthread_barrier_init().

Write our own simple barrier:

pthread_mutex_lock(&m);
remain --;
if(remain == 0){
    pthread_cond_broadcast(&cv);
}
while(remain > 0){
    pthread_cond_wait(&cv,&m);
}
pthread_mutex_unlock(&m);
复制代码

Part 5: Reader/Writer problen

reader(){
    lock(&m);
    while(writer) pthread_cond_wait(&cv, &m);
    read++
    unlock(&m);
    
    lock(&m)
    read--;
    pthread_cond_broadcast(&cv);
    unlock(&m);
}
writer(){
    lock(&m);
    writer++;
    while(writer || reader) pthread_cond_wait(&cv,&m);
    writer++;
    unlock(&m);
    
    lock(&m);
    writer--;
    writer--;
    pthread_cond_broadcast(&cv);
    unlock(&m);
}
复制代码

Deadlcok

Coffman conditions

  • Mutex Exclusion: The resource cannot be shared
  • Circular Wait: There exists a cycle in the Resource Allocation Graph
  • Hold and Wait: Holding some resource and waiting for the resource holded by others
  • No pre-emption: The resource can't be taken away by other thread

Dining Philosophers

  • Left-right Deadlock will lead to circle wait. Hold left and wait for right.
  • Trylock? will cause a livelock.
    1. Arbitrator 2. Leave table 3. All choose lower

Exam Practice

1. Define circular wait, mutual exclusion, hold and wait, and no-preemption. How are these related to deadlock?

circular wait: There exist a circle in Resource Allocation Graph. hold and wait: Thread will holding the current resource while waiting for the resource hold by others mutual exclusion: The resource can't be shared no-preemption: Resource can't be taken by others.

2. What problem does the Banker's Algorithm solve?

Deadlock

3. What is the difference between Deadlock Prevention, Deadlock Detection and Deadlock Avoidance?

4. Sketch how to use condition-variable based barrier to ensure your main game loop does not start until the audio and graphic threads have initialized the hardware and are ready.

5. Implement a producer-consumer fixed sized array using condition variables and mutex lock.

6. Create an incorrect solution to the CSP for 2 processes that breaks: i) Mutual exclusion. ii) Bounded wait.

7. Create a reader-writer implementation that suffers from a subtle problem. Explain your subtle bug.

转载于:https://juejin.im/post/5c1328d2f265da61561f24d4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值