加载中…
个人资料
南冠彤
南冠彤
  • 博客等级:
  • 博客积分:0
  • 博客访问:415,028
  • 关注人气:59
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
谁看过这篇博文
加载中…
正文 字体大小:

(转)死锁检测

(2011-06-28 14:25:17)
标签:

杂谈

分类: CPP/C

曾经参与过的一款网络游戏,其服务器使用了异常复杂的多线程序解决方案。导致应用层程序员编写的代码很容易就出现死锁。

最终,公司的一个老员工,只能开发了一个死锁检测框架,在debug模式下运行时,只要发生死锁就会打印出调用堆栈。

虽然说这个框架基本可以在上线前把所有的死锁都检测了出来,但是,规根到底这是设计不合理造成的,多线程利用好了会提升

应用的效率,用不好的话,除了影响效率外,对上层开发简直是灾难。

下面说说那个检测方法,其实方法挺简单的。

有两个容器,一个用于保存线程正在请求的锁,一个用于保存线程已经持有的锁。

每次加锁之前都会做如下检测:

1)检测当前正在请求的锁是否已经被其它线程持有,如果有,则把那些线程找出来

2)遍历第一步中返回的线程,检查自己持有的锁是否正被其中任何一个线程请求

 如果第二步返回真,表示出现了死锁

下面是简单的实现:

appMutex.h

view plaincopy to clipboardprint?
#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()  
        
             
            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 
#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()
  {
   
      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

view plaincopy to clipboardprint?
#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__);  

#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();


}

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/sniperhuangwei/archive/2010/01/27/5262726.aspx

0

阅读 评论 收藏 转载 喜欢 打印举报/Report
后一篇:rtmp协议详解
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

    后一篇 >rtmp协议详解
      

    新浪BLOG意见反馈留言板 电话:4000520066 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有