死锁
1、死锁产生的条件
死锁只有同时满足一下四个条件才会发生:
(1)互斥条件
互斥条件是指,多个线程不能同时使用同一个资源。
(2)持有并等待条件
持有并等待条件是指,当线程A已经持有了资源1,又想申请资源2,而资源2已经被线程B持有了,所以线程就会处于等待状态,但是线程A在等待资源2的同时并不会释放自己已经持有的资源1。
(3)不可剥夺条件
不可剥夺条件是指,当线程已经持有了资源,在自己使用完之前不能被其他线程获取。
(4)循环等待条件
循环等待条件是指,在死锁发生的时候,多个线程获取资源的顺序构成了环形链。
2、模拟死锁问题的产生
首先,我们先创建两个线程,分别为线程A和线程B,然后有两个互斥锁,分别是 mutex_A 和 mutex_B,代码如下:
pthread_mutex_t mutex_A = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_B = PTHREAD_MUTEX_INITIALIZER;
int main()
{
pthread_t tidA, tidB;
//创建两个线程
pthread_create( &tidA, NULL, threadA_proc, NULL );
pthread_create( &tidB, NULL, threadB_proc, NULL );
pthread_join(tidA, NULL);
pthread_join(tidB, NULL);
printf("exit\n");
return 0;
}
//线程函数 A
void *threadA_proc(void *data)
{
printf("thread A waiting get ResourceA \n");
pthread_mutex_lock( &mutex_A );
printf("thread A got ResourceA \n");
sleep(1);
printf("thread A waiting get ResourceB \n");
pthread_mutex_lock(&mutex_B);
printf("thread A got ResourceB \n");
pthread_mutex_unlock(&mutex_B);
pthread_mutex_unlock(&mutex_A);
return (void *) 0;
}
//线程函数B
void *threadB_proc(void *data)
{
printf("thread B waiting get ResourceB \n");
pthread_mutex_lock( &mutex_B );
printf("thread B got ResourceB \n");
sleep(1);
printf("thread B waiting get ResourceA \n");
pthread_mutex_lock(&mutex_A);
printf("thread B got ResourceA \n");
pthread_mutex_unlock(&mutex_A);
pthread_mutex_unlock(&mutex_B);
return (void *) 0;
}
3、避免死锁问题的发生
前面提到产生死锁的四个必要条件是:互斥条件、持有并等待条件、不可剥夺条件和循环等待条件。
那么避免死锁问题就只需要破坏其中一个条件就可以,最常见的并且可执行的就是使用资源有序分配法,来破坏循环等待条件。
什么是资源有序分配法呢?
线程A和线程B获取资源的顺序要一样,当线程A是先尝试获取资源A,然后尝试获取资源B的时候,线程B同样也是先尝试获取资源A。然后尝试获取资源B,也就是说,线程A和线程B总是以相同的顺序申请自己想要的资源。
我们使用资源有序分配法的方式来修改前面发生死锁的代码,我们可以不改动线程A的代码,只改动线程B的代码。
线程B函数改进后的代码如下:
//线程 B 的函数,同线程A一样,先获取互斥锁A,再获取互斥锁B
void *threadB_proc(void *data)
{
printf("thread B waiting get ResourceA \n");
pthread_mutex_lock( &mutex_A );
printf("thread B got ResourceA \n");
sleep(1);
printf("thread B waiting get ResourceB \n");
pthread_mutex_lock(&mutex_B);
printf("thread B got ResourceB \n");
pthread_mutex_unlock(&mutex_B);
pthread_mutex_unlock(&mutex_A);
return (void *) 0;
}
总结
简单来说,死锁问题的产生是由两个或者以上线程并行执行的时候,争夺资源而相互等待造成的。
死锁只有同时满足互斥、持有并等待、不可剥夺和环路等待四个条件的时候才会发生。
所以要避免死锁问题,就是要破坏其中一个条件即可,最常用的方法就是使用资源有序分配法来破坏环路等待条件。