浅谈死锁破除和优化
来源:互联网 发布:软件系统项目总结报告 编辑:程序博客网 时间:2024/05/19 13:07
死锁的四个必要条件:请求和保持、互斥、不可剥夺、循环等待。
--死锁条件-----破除方法--
请求和保持 : 预先分配
互斥:虚拟资源
不可剥夺:可剥夺,死锁检测之后就中止最后导致死锁的进程
循环等待:按序申请资源
按序申请资源破除循环等待的证明:
假设有一组按序申请资源且循环等待的进程:{P0,P1,P2,…,Pn},其中Pi拥有资源Ri,Ri编号为F(Ri),根据按序分配原则,有 F(R0)<F(R1)<…<F(Rn),因存在循环等待,所以Pn所申请的下一个资源应为P0所占的资源R0;若Pn能正常运行,则应依据资源按序分配,即下次申请资源编号应比它所占资源编号大,即有F(Rn)<F(R0),此结论与不等式中F(R0)<F(Rn)矛盾,所以不存在循环等待。
常用的办法是进行按序申请资源。但是条件非常苛刻的情况下,为了更快的整体运行速度,可以允许一部分进程预先使用序号大的资源。这时的处理方式是:不可剥夺变为可剥夺。因为不可剥夺变成可剥夺,允许死锁出现,更多的进程可以无等待推进,直到出现死锁才由系统来解决。所以需要死锁检测,找到造成死锁的进程,然后对造成死锁的进程进行死锁状态回滚并暂停其运行,等预判其运行不会造成死锁时再重新申请执行。
这里一共要做四件事:
1、死锁检测
2、进程状态回滚并暂停其运行
3、预判死锁
4、重新执行
死锁检测:
1、使用操作系统API对应提供的工具:检测工具见《Windows核心编程》,第9章9.8.6节LockCop检测工具
2、自己写代码检测:参考链接
appMutex.h
#ifndef _APPMUTEX_H#define _APPMUTEX_H#include <iostream>#include "lock.h"#include <map>#include <list>class appMutex;static Lock gMtx;//记录了线程当前正在请求的锁class mtxReqMgr{public: static bool check(pthread_t pid); static void reqMutex(appMutex *mtx); static void clearReq(appMutex *mtx);private: static std::map<pthread_t,appMutex*> reqMap;//每个线程只可能请求一个锁};//记录了线程已经持有的锁class mtxHoldMgr{public: static bool check(pthread_t pid,appMutex *mtx); static bool check(appMutex *mtx,std::list<pthread_t> &ret); static void hold(appMutex *mtx); static void release(appMutex *mtx); //释放掉所有已经持有的锁 static void releaseAll(); private: static std::map<pthread_t,std::list<appMutex*> > holdMap;//每个线程可能拥有好几个锁};class appMutex : private Lock{ friend class mtxHoldMgr; public: appMutex(const char *name):name(name) {} void lock() { /*这里执行死锁检测,检测规则 1)检测当前正在请求的锁是否已经被其它线程持有,如果有,则把那些线程找出来 2)遍历第一步中返回的线程,检查自己持有的锁是否正被其中任何一个线程请求 如果第二步返回真,表示出现了死锁 */ std::list<pthread_t> mtxHolds; if(mtxHoldMgr::check(this,mtxHolds)) { std::list<pthread_t>::iterator it = mtxHolds.begin(); std::list<pthread_t>::iterator end = mtxHolds.end(); for( ; it != end; ++it) { if(mtxReqMgr::check(*it)) { mtxHoldMgr::releaseAll(); printf("dead lock in require %s,thread:%u/n",name.c_str(),pthread_self()); exit(0); } } } mtxReqMgr::reqMutex(this); Lock::lock(); mtxReqMgr::clearReq(this); mtxHoldMgr::hold(this); } void unlock() { Lock::unlock(); mtxHoldMgr::release(this); } private: void release()//只有在出现死锁时才会调用 { Lock::unlock(); } private: std::string name;};#endif
appMutex.cpp
#include "appMutex.h"std::map<pthread_t,appMutex*> mtxReqMgr::reqMap;std::map<pthread_t,std::list<appMutex*> > mtxHoldMgr::holdMap;//释放掉所有已经持有的锁void mtxHoldMgr::releaseAll(){ Scope_lock _guard(gMtx); pthread_t pid = pthread_self(); std::map<pthread_t,std::list<appMutex*> >::iterator it = holdMap.find(pid); if(it != holdMap.end()) { while(!it->second.empty()) { appMutex *_appmtx = it->second.back(); it->second.pop_back(); _appmtx->release(); } }}bool mtxReqMgr::check(pthread_t pid){ Scope_lock _guard(gMtx); pthread_t selfpid = pthread_self(); std::map<pthread_t,appMutex*>::iterator it = reqMap.find(pid); if(it != reqMap.end() && it->second != NULL) { return mtxHoldMgr::check(selfpid,it->second); } return false;}void mtxReqMgr::reqMutex(appMutex *mtx){ Scope_lock _guard(gMtx); pthread_t pid = pthread_self(); std::map<pthread_t,appMutex*>::iterator it = reqMap.find(pid); if(it == reqMap.end()) { reqMap.insert(std::make_pair(pid,mtx)); } else { it->second = mtx; }}void mtxReqMgr::clearReq(appMutex *mtx){ Scope_lock _guard(gMtx); pthread_t pid = pthread_self(); std::map<pthread_t,appMutex*>::iterator it = reqMap.find(pid); if(it != reqMap.end()) it->second = NULL; else { printf("it must be error %s %d /n",__FILE__,__LINE__); }}bool mtxHoldMgr::check(pthread_t pid,appMutex *mtx){ Scope_lock _guard(gMtx); std::map<pthread_t,std::list<appMutex*> >::iterator it = holdMap.find(pid); if(it != holdMap.end()) { std::list<appMutex*>::iterator lit = it->second.begin(); std::list<appMutex*>::iterator lend = it->second.end(); for( ; lit != lend; ++lit) { if(mtx == *lit) { return true; } } } return false;}bool mtxHoldMgr::check(appMutex *mtx,std::list<pthread_t> &ret){ Scope_lock _guard(gMtx); pthread_t pid = pthread_self(); std::map<pthread_t,std::list<appMutex*> >::iterator it = holdMap.begin(); std::map<pthread_t,std::list<appMutex*> >::iterator end = holdMap.end(); for( ; it != end; ++it) { if(it->first == pid) continue; std::list<appMutex*>::iterator lit = it->second.begin(); std::list<appMutex*>::iterator lend = it->second.end(); for( ; lit != lend; ++lit) { if(mtx == *lit) { ret.push_back(it->first); break; } } } return !ret.empty();}void mtxHoldMgr::hold(appMutex *mtx){ Scope_lock _guard(gMtx); pthread_t pid = pthread_self(); std::map<pthread_t,std::list<appMutex*> >::iterator it = holdMap.find(pid); if(it == holdMap.end()) { std::list<appMutex*> tmp; tmp.push_back(mtx); holdMap.insert(std::make_pair(pid,tmp)); } else { it->second.push_back(mtx); }}void mtxHoldMgr::release(appMutex *mtx){ Scope_lock _guard(gMtx); pthread_t pid = pthread_self(); std::map<pthread_t,std::list<appMutex*> >::iterator it = holdMap.find(pid); if(it != holdMap.end()) { if(mtx != it->second.back()) { //释放锁的顺序跟加锁的顺序不一致 printf("it must be error %s %d /n",__FILE__,__LINE__); } else it->second.pop_back(); } else printf("it must be error %s %d /n",__FILE__,__LINE__);}
在两线程中分别如下调用,则会出现死锁警告
appMutex a("a");appMutex b("b"); threada:while(1){a.lock();Thread::sleep(1);b.lock();b.unlock();a.unlock();} threadb:while(1){b.lock();a.lock();a.unlock();b.unlock();}
伪代码:
while (p.checkDeadlock() == true){p.suspend();sleep(time);p.resume();}
虚拟资源破除死锁的话,就以虚拟内存为例。32位系统默认分配4G内存,物理内存没有4G,又要运行多进程,则可以理解为很多进程的执行需要依赖于共享资源4G内存。按之前的做法,进程都要等待有4G内存才执行。而虚拟内存,是通过将外存模拟为内存,虽然速度会慢一些,但是解决了进程的分段执行的基本条件。这一段的问题以后第三篇再详谈其实现。
除了前面提到的三种破除,最后一种就是效率比较低,但是比按序申请效率高的预先分配了,最典型的就是银行家算法。下一篇详述银行家算法。
- 浅谈死锁破除和优化
- 浅谈死锁
- 浅谈死锁
- 浅谈死锁
- 浅谈死锁
- 浅谈死锁
- SQL Server 死锁处理和优化心得
- 浅谈Oracle死锁问题
- 线程死锁浅谈
- 浅谈Linux死锁检测
- 内存优化之浅谈onLowMemory和onTrimMemory
- 浅谈rowid和性能优化的关系
- 浅谈android网络和电量优化
- 浅谈Sql 死锁(Dead Lock)
- 浅谈linux的死锁检测
- 浅谈线程同步的死锁
- 浅谈线程同步的死锁
- Java_浅谈死锁的产生
- soapHandler
- android--List属性
- iOS开发Xcode中导入Pch预编译文件
- UGUI基本属性设置
- linux文件的压缩解压缩
- 浅谈死锁破除和优化
- 面试题目总结2
- PyQt5 - QWidgets部件进阶教程之数字时钟
- 集成七牛云储存-上传图片Demo
- Gulp and Grunt
- 产品经理--2竞品分析
- zedgraph控件使用
- keepalived+twemproxy部署redis集群高可用
- 动态规划求最长公共子序列长度和子序列