先了解下什么叫做死锁:
一个或多个变量被可执行程序的其中一个线程锁住了,其他线程都无法访问这个资源,被阻塞在对这个资源访问前,但是锁住这个资源的线程本身也被锁住了,它也被阻塞在对这个资源访问的前面。
那么为什么锁住资源的线程本身也被锁住了呢,这就是死锁产生的原因,比如这个线程锁住了资源,但是离开时忘记解锁,因此下次再来访问时也被阻塞住了。
下面是一些死锁的情况,以下是伪代码:
1,加锁之后忘记解锁
void funcA()
{
for (int i = 0; i < 10; i++)
{
//第二次循环到这得时候就会被锁住
pthread_mutex_lock(&mutex);
.........
//忘记解锁,下面进入下一次循环
}
}
void funcA()
{
//第二次循环到这得时候就会被锁住
pthread_mutex_lock(&mutex);
.........
//忘记解锁,下面进入下一次循环
if(...)
{
...
return NULL;//从这里返回后,依然没有解锁就离开了,会阻塞住其他线程,本线程下次再次访问这些被锁住的资源也会被锁住,这是锁的机制,一把锁,如果没有解锁,即使是加锁的线程也不能再次加锁。
}
pthread_mutex_unlock(&mutex);
}
2.重复加锁
void funcA()
{
//第二次循环到这得时候就会被锁住
pthread_mutex_lock(&mutex);
.........
.........
.........
pthread_mutex_lock(&mutex);//重复加锁,这时会阻塞在这里
........
pthread_mutex_unlock(&mutex);
}
还有隐藏的比较深的
void funcB()
{
//第二次循环到这得时候就会被锁住
pthread_mutex_lock(&mutex);
.........
.........
.........
........
pthread_mutex_unlock(&mutex);
}
void funcA()
{
//第二次循环到这得时候就会被锁住
pthread_mutex_lock(&mutex);
.........
.........
.........
funcB();//在这里调用,使得重复加锁,会阻塞在funcB()的加锁代码语句前
........
pthread_mutex_unlock(&mutex);
}
以上两种情况可以归结为犯了锁的一个机制,因此被阻塞:一把锁,如果没有解锁,所有线程即使是加锁的线程本身,也不能再次加锁,只会被阻塞。
3,资源比较多,互相访问
有线程A,B
资源int_a,int_b
A加锁了int_a
B加锁了int_b
之后:
A去访问了int_b,这时B也访问了int_a。
因为int_b被B加锁了,所以A在访问它之前被阻塞住了
因为int_a被A加锁了,所以B在访问它之前也被阻塞住了
因为A,B都被阻塞住了,因此他们都不能解锁自己锁住的资源。
它两线程就这么互相绷住了…
那么怎么防止死锁呢,加锁后一定要记得解锁,避免重复加锁。
加锁函数可以使用trylock,这个函数会尝试加锁,如果无法加上也不会阻塞。