死锁通常是因为获取锁时形成了环路。
死锁发生前
- 尽量不要使用共享 例如使用消息通讯,例如Erlang里的变量不变
- 尽量使用并发组件 例如java.util.concurrent
- 尽量使用非递归锁(不可重入锁) 例如pthread_mutex_t默认非递归
- 控制顺序 thread 1: Lock(a), Lock(b) thread 2: Lock(b), Lock(a) 转变为统一的顺序如Lock(a), Lock(b)
- 运行期警告 把Lock(历史)形成一个graph,看是否存在回路
- 超时机制 如带有timeout的wait, innodb_lock_wait_timeout等
- 工具测试 例如Intel inspector, Valgrind-Helgrind(pthread)等
- PS. 银行家算法 由Edsger Dijkstra爷爷为设计THE操作系统创建,其使用场景也有些局限性,比如需要知道进程请求资源的可能数量,以及假设进程数量是固定的等,因此基本不具有实用性。
死锁发生后
- 堆栈查看 pstack(其实就是gdb thread apply all bt) jstack, jconsole ps. CPU100%也可以通过这种方法
- 检测机制 例如innodb的wait-for graph,形成环路(或者层次太深时也会认为死锁)时,此时会选择Undo量小的事务进行回滚。