死锁问题分析及解决办法

来源:互联网 发布:可以赚钱的软件 编辑:程序博客网 时间:2024/06/05 07:36
死锁问题:
出现条件,至少两个线程,两把锁。
举例:
两个线程为甲和乙, 两把锁为A 和 B.
甲线程申请了锁A, 再申请锁B, 才能完成工作。
乙线程申请了锁B, 再申请锁A, 才能完成工作。
当甲线程申请到锁A, 等待锁B, 乙线程申请到锁B, 等待锁A, 就造成死锁。
死锁后,甲,乙两线程均不能运行。

解决办法: 打破这种互套关系即可。
如果两把锁可以不互相嵌套, 则死锁解除。
例如: 乙线程申请了锁B, 完成部分工作,然后释放锁B, 再申请锁A, 完成部分工作,再释放锁A.  则死锁解除。
数据锁要仅保护数据,不保护未知调用。

若两把锁必须互相嵌套, 则需要延时等待。 例如两个人1双筷子吃饭问题。

下面举例:数据锁,锁不互相嵌套的例子:
举例: // 关闭特定的demux filter
要求: 有一个map, 装有<handle, [reqid,pid]>,
现在已知reqid,pid, 要删掉这条记录。
说明:
1.这个map, 多个线程使用,所以,对它的增,删,改,查要加锁。
2. 删除map 数据项,要同时调用一个函数叫tsdemux_delSectionFilter, 来删除demux 端的filter.
   tsdemux_delSectionFilter 函数也是一个多线程调用函数, 它的操作也有一把锁。
注意点:数据保护锁,最好仅对数据操作保护, 不要保护其他函数,
因为其他函数,你可能不知道它干了什么。会不会也有锁, 会不会造成锁嵌套。

甲: 有问题的程序:(可能会死锁)
void CloseGMapDemuxFilter_Lock(map<HANDLE,RegIDPID>& map_hFilter_ReqIDPID,CDCA_U8  byReqID,    CDCA_U16 wPid, MutexT & mutex)
{
    AutoLockT lockIt(mutex);            // 申请了A 锁
    map<HANDLE,RegIDPID>::iterator it;
    for(it=map_hFilter_ReqIDPID.begin(); it!=map_hFilter_ReqIDPID.end();it++)
    {
        if(it->second.byReqID == byReqID && it->second.wPid == wPid)
        {
            dxreport("delete filter, byReqID:%d wPid:0x%x\n", byReqID, wPid);
// 两个锁互相嵌套,满足死锁条件。当有人申请了B 锁,调用本函数,易死锁
// tsdemux_delSectionFilter函数会申请 B 锁,该函数执行需要先申请A锁,再申请B锁才能执行,形成锁嵌套. 如果有其他函数同样考虑不周,会形成死锁。

// 例如: 线程2 首先调用该函数,申请了A 锁,还没有申请到B 锁, 不幸被切换走了

// 线程1调用 setsectionfilter 申请了B锁,再来调用该函数。它申请不到A 锁(被线程2占着),只能阻赛与此函数中。

// 线程2 时间片到,恢复执行,却申请不到 B 锁(被线程1占着),也只能阻塞欲此函数内,结果形成了死锁。

// 尽管考虑了同线程,不可重复申请同一把锁,避免了一个线程中死锁。(windows EnterCriticalSection 同线程可以反复进入)

            //  或者privateDataCallBack 申请了B锁,再来调用该函数
            tsdemux_delSectionFilter(it->first,NULL);    // 这个函数,不应该被保护
            handle = it->first;
            map_hFilter_ReqIDPID.erase(it);
            break;
        }
    }

}

乙: 解决问题后程序:(锁不能嵌套,解出耦合,不会死锁)
void CloseGMapDemuxFilter_Lock(map<HANDLE,RegIDPID>& map_hFilter_ReqIDPID,CDCA_U8  byReqID,    CDCA_U16 wPid, MutexT & mutex)
{
    HANDLE handle = 0;      // 被调用函数会用到的参数
    {
        AutoLockT lockIt(mutex);         // A 锁,不套用B 锁
        map<HANDLE,RegIDPID>::iterator it;
        for(it=map_hFilter_ReqIDPID.begin(); it!=map_hFilter_ReqIDPID.end();it++)
        {
            if(it->second.byReqID == byReqID && it->second.wPid == wPid)
            {
                dxreport("delete filter, byReqID:%d wPid:0x%x\n", byReqID, wPid);
                //tsdemux_delSectionFilter(it->first,NULL); 这个函数不能用该锁保护。
                handle = it->first;      // 保留数据,供该锁外处理。
                map_hFilter_ReqIDPID.erase(it);
                break;
            }
        }
    }
    if(handle!=0)  // 调用含B 锁的函数
    {
        tsdemux_delSectionFilter(handle,NULL);
    }

}

丙:另一个例子:
void CloseGMapDemuxFilters_Lock(map<HANDLE,RegIDPID>& map_hFilter_ReqIDPID, MutexT & mutex)
{
    map<HANDLE,RegIDPID> tmp;    // 保留第二步数据
    map<HANDLE,RegIDPID>::iterator it;

    //关闭已有的filters 列表
    {
        AutoLockT lock_it(mutex);
        tmp = map_hFilter_ReqIDPID;    // 保留数据,供该锁外处理
        for(it=map_hFilter_ReqIDPID.begin(); it!=map_hFilter_ReqIDPID.end();it++)
        {
//            tsdemux_delSectionFilter(it->first,NULL);   //这个函数,不应该被保护,如果不提取出来会死锁
            map_hFilter_ReqIDPID.erase(it);
        }
    }
    for(it=tmp.begin(); it!=tmp.end();it++) // 分两步走,不死锁
    {
        tsdemux_delSectionFilter(it->first,NULL);
    }
}


原创粉丝点击