浅谈死锁破除和优化

来源:互联网 发布:软件系统项目总结报告 编辑:程序博客网 时间: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();}


死锁检测之后,释放关键资源,暂停进程。直接调用suspend有关的api即可。等待一段时间之后,再次执行申请关键资源之后,再执行死锁检测。直到不会死锁可以运行该进程为止。
伪代码:

while (p.checkDeadlock() == true){p.suspend();sleep(time);p.resume();}

虚拟资源破除死锁的话,就以虚拟内存为例。32位系统默认分配4G内存,物理内存没有4G,又要运行多进程,则可以理解为很多进程的执行需要依赖于共享资源4G内存。按之前的做法,进程都要等待有4G内存才执行。而虚拟内存,是通过将外存模拟为内存,虽然速度会慢一些,但是解决了进程的分段执行的基本条件。这一段的问题以后第三篇再详谈其实现。


除了前面提到的三种破除,最后一种就是效率比较低,但是比按序申请效率高的预先分配了,最典型的就是银行家算法。下一篇详述银行家算法。

0 0
原创粉丝点击