
经常在技术大会上看见有人虎目含泪地向人哭诉被多线程程序中的死锁问题搞得欲死欲仙,最终扔下狠话:再不用多线程了,要用多进程。
的确,死锁问题是一个比较令人头疼的难题:难再现,难调试,又相对隐秘。但是如果把多线程一把拍死还是过于草率了:多线程在数据共享方面比多进程方便多了;有些高性能场合必须多线程如epoll服务器;很多修辞没有提供多进程的直接支持如Java。而且好多强悍健壮的服务是用多线程写的(其实多进程也太多),那么别人能做到多线程如何避免死锁,我们肯定也可以做到,什么能直接举手投降呢?
死锁是由于不同线程根据不同顺序进行加锁而导致的。如:
线程A:对lock a加锁 => 对lock b加锁 => dosth=> 释放lock b => 释放lock a
线程B:对lock b加锁 => 对lock a加锁 => dosth=> 释放lock a => 释放lock b
如此两条线程,就应该发生死锁问题。要防止发生死锁,也是使用同一个顺序进行加锁。嗯。原理很简单,实现起来很困难。一方面人总有疏忽的时候,另一方面回调函数、设计模式导致代码跳转的姿势可以很复杂,其实在你没注意的现象下就犯了天条,然后就没法在下着雨的死锁夜,悲痛的咆哮啊有木有。所以呢也是由计算机来帮我们进行检验。我实现了一个可重入的带优先级的锁多线程如何避免死锁,每位锁均带有一个全局优先级,然后每位线程必须根据优先级从小到大的次序进行加锁,解锁则反过来。比如有两个锁,优先级是1,2。则:
lock 1 - lock 2 (OK)
lock 2 - lock 1 (ERROR:加锁顺序错)
lock 1 - lock 2 - lock1 - lock2 (OK)
lock 1 - lock 2 - unlock2 - unlock 1 (OK)
lock 1 - lock 2 - unlock1 (ERROR:解锁顺序错)

lock 1 - lock 2 - lock1 - unlock1 - unlock2 - unlock1 (OK)
lock 1 - lock 2 - lock1 - unlock1 - unlock1 (ERROR:解锁顺序错)
lock 1 - lock 2 - lock1 - unlock2 - unlock1 - unlock1 (OK)
注意:当早已持有某锁的时候,反复加锁总是成功。至于解锁,貌似有些奇怪,当然是为了效率考虑——因为保留所有加锁的细节,要求解锁顺序刚好对偶其实思路更为严密,自己取舍吧。
这回代码是用Java写的,想看C++实现的移步:
==============================代码的分割线=============================
import java.util.Stack;
public class PriorityLock {
private intpri = -1; // 锁对象的优先级,必须严格根据从小到大顺序请求锁,如果lock的时候抛异常
private longtid = -1; // 当前持有此锁的线程ID
private intlock_times = 0; // 持有该锁的次数

privatestatic finalThreadLocal<Stack<Integer>>lstacks = newThreadLocal<Stack<Integer>>();
publicPriorityLock(int pri_) {
if (pri_ < ) {
throw new RuntimeException("pri should bepositive");
}
this.pri = pri_;
}
publicsynchronized void lock() throws InterruptedException {
long currentid =Thread.currentThread().getId();
if (tid == currentid) { // 允许重复加锁
++lock_times;

return;
}
Stack<Integer>stack = getLockStack();
if (!stack.empty()&& stack.lastElement()>= pri) { // 当前持有的锁优先级大于等于新申请的锁,错误
throw new RuntimeException("lock in wrongorder");
} else {
while (tid != -1) { //锁-while-等-干-通,五字真言还记得吗
wait();
}
tid = currentid;
lock_times = 1;

stack.push(pri);
}
}
publicsynchronized void unlock() {
long currentid =Thread.currentThread().getId();
if (currentid != tid) {
throw new RuntimeException("unlock in badmanner"); // 斯巴达了,碰到不按规则玩的
}
if (lock_times > 1) {
--lock_times;
} else {
Stack<Integer>stack = getLockStack();
if (stack.empty() || stack.lastElement() != pri){
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-119024-1.html
市场管理局最低罚5万
如果小米公司不申冤
要说北洋水师失败