系统环境 centos6.5
什么是死锁
是指两个或两个以上的进程(线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外部处理作用,它们都将无限等待下去。
- 死锁原因
系统资源不足;
进程(线程)推进的顺序不恰当;
资源分配不当;
死锁产生的4个必要条件
- 互斥条件:所谓互斥就是进程在某一时间内独占资源。
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
常见死锁形成的场景
死锁形成的常见情况有以下几种:
** 忘记释放锁**
void data_process()
{
EnterCriticalSection();
if(/* error happens, forget LeaveCriticalSection */)
return;
LeaveCriticalSection();
}
** 单线程重复申请锁**
void sub_func()
{
EnterCriticalSection();
do_something();
LeaveCriticalSection();
}
void data_process()
{
EnterCriticalSection();
sub_func();
LeaveCriticalSection();
}
** 多线程多锁申请**
void data_process1()
{
EnterCriticalSection(&cs1); // 申请锁的顺序有依赖
EnterCriticalSection(&cs2);
do_something1();
LeaveCriticalSection(&cs2);
LeaveCriticalSection(&cs1);
}
void data_process2()
{
EnterCriticalSection(&cs2); // 申请锁的顺序有依赖
EnterCriticalSection(&cs1);
do_something2();
LeaveCriticalSection(&cs1);
LeaveCriticalSection(&cs2);
}
** 环形锁申请**
/* 多个线程申请锁的顺序形成相互依赖的环形:
* A - B
* | |
* C - D
*/
如何避免死锁?常见算法与原理
- 时刻检查自己写的程序有没有在跳出时忘记释放锁。
- 如果自己的模块可能重复使用一个锁,建议使用嵌套锁。
- 对于某些锁代码,不要临时重新编写,建议使用库里面的锁,或者自己曾经编写的锁。
- 如果某项业务需要获取多个锁,必须保证锁的按某种顺序获取,否则必定死锁。
- 编写简单的测试用例,验证有没有死锁。
- 编写验证死锁的程序,从源头避免死锁。
要预防和避免死锁的发生,只需将上面所讲到的4个条件破坏掉其中之一即可。一般而言破坏“循环等待”这个条件是解决死锁最有效的方法。
网友评论