Chinaunix首页 | 论坛 | 博客
  • 博客访问: 541988
  • 博文数量: 493
  • 博客积分: 2891
  • 博客等级: 少校
  • 技术积分: 4960
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-17 17:11
文章分类

全部博文(493)

文章存档

2010年(493)

分类:

2010-05-12 18:22:44

1 现象:问题描述
多线程map无保护操作,引起map的查找操作出现问题,导致预处理程序停止处理话单。
2 关键过程:根本原因分析
int CProcBillImp::EndAFile(UINT4 nFileSN)
{
    int nRet = 0;
    TFileStat* pFileStat = m_pFileHouse->GetFileStat(nFileSN);
    if(pFileStat != NULL)
    {
        pFileStat->nAnswerCount++;       
        //如果该文件的"结束应答"消息个数等于处理通道个数,
        //则结束该文件的处理
        if(pFileStat->nAnswerCount >= m_nProcChlNum)
        {
            char szFileName[MAX_PATH];
            const TCollectInfo* pInfo = m_pFileHouse->GetCollectInfo(pFileStat->nCollectNo);
            SNPRINTF(szFileName, MAX_PATH, "%s/%s/%s", pInfo->sName.c_str(),
                      pFileStat->szMidPath, pFileStat->szFileName);
            //结束每一个类型通道中该文件对应的错单文件
            // … …
TFileStat* CFileHouseImp::GetFileStat(UINT4 nFileSN)
{
    FILE_STAT::iterator it = m_FileStatList.find(nFileSN);
    if(it != m_FileStatList.end())
    {
        return it->second;
    }
   
    return NULL;
}
在FileHouse中保存一个当前正在处理的话单文件列表。
这个列表由两个线程进行操作:
话单处理线程将处理过的话单加入这个列表;
话单结束线程从这个列表中删除已经成功结束处理的话单文件。
由于在取得列表时没有加锁,在多线程竞争的情况下,会在查找文件ID的时候,其他线程在改变map元素的个数,导致找不到与文件ID对应的文件状态对象。也就是这个文件状态对象会一直保留在文件列表中。当列表的长度大于3后,话单处理线程会停止处理文件
3 结论:解决方案及效果
在文件状态列表中查找对象前加锁控制线程并发,保证在查找的时候,不会有map的插入操作(只为一个线程所有,删除和查找为一个线程)
TFileStat* CFileHouseImp::GetFileStat(UINT4 nFileSN)
{
    m_MutexForStat.acquire();
   
    FILE_STAT::iterator it = m_FileStatList.find(nFileSN);
    if(it != m_FileStatList.end())
    {
         TFileStat* filsStat = it->second;
        m_MutexForStat.release();
     
        return filsStat;
    }
    m_MutexForStat.release();
    char szTmpBuf[g_nTmpBuffLen];
    SNPRINTF(szTmpBuf, g_nTmpBuffLen, "%s%d", CONVERT_MOD_NAME, m_nModNo);
    szTmpBuf[g_nTmpBuffLen - 1] = '\0';
    TRACE(szTmpBuf, "Can not find the stat of file(%8d)",nFileSN);   
    return NULL;
}
4 经验总结:预防措施和规范建议
当在多线程环境下,某些提供读写方法的容器对象的操作需要注意对其进行操作保护,保证数据正确性。
5 备注
6 考核点
多线程,容器,同步保护。
7 试题
std::map MapOpName;
MapOpName opName;
std:string ThreadA::GetOpName
{
 //查找OperatorName
    MapOpName::iterator it = opName.find(m_nIMSI);
    if (it != opName.end())
    {
  return it.second();
    }
}
TheadB::ClearData()
{
     MapOpName::iterator it = opName.begin();
     while(it != opName.end())
     {
         delete it->second;
          ++it;
    }
}
对这段代码下面说法中正确的是:BC
A、代码正确,没有问题;
B、代码在多线程环境下会发生不可知的错误;
C、在单线程下代码能够正确工作;
D、以上说法都不对。
阅读(579) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~