死锁问题:
出现条件,至少两个线程,两把锁。
举例:
两个线程为甲和乙, 两把锁为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锁才能执行,形成锁嵌套. 如果有其他函数同样考虑不周,会形成死锁。
// 或者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);
}
}
出现条件,至少两个线程,两把锁。
举例:
两个线程为甲和乙, 两把锁为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占着),也只能阻塞欲此函数内,结果形成了死锁。
// 或者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);
}
}