MDGSF Software Engineer

[C/C++] 线程加锁 例子

2016-05-30

    apr_thread_mutex_lock(m_pstMutex);
    apr_int32_t iMaxTryTime = m_oLBServerVector.size();
    apr_thread_mutex_unlock(m_pstMutex);
    while ( iMaxTryTime-- > 0 )
    {
        char acServerIPAddr[MAX_IPADDRESS_LENGTH] = {0};
        apr_uint32_t uiServerPort;

        apr_thread_mutex_lock(m_pstMutex);
        vector<SServerAddr>::iterator oLBIter = m_oLBServerVector.begin();
        strcpy(acServerIPAddr, oLBIter->m_acServerIPAddr);
        uiServerPort = oLBIter->m_uiServerPort;
        apr_thread_mutex_unlock(m_pstMutex);

        iRet = m_iQueryFromServerTCP(
                acServerIPAddr,
                uiServerPort,
                acSendMsgBuf,
                usSendMsgLen,
                acRecvMsgBuf,
                &usRecvMsgLen,
                &ucMsgType);
        if(APR_SUCCESS == iRet) {
            break;
        }

        apr_thread_mutex_lock(m_pstMutex);
        SServerAddr stServerAddr = *oLBIter;
        m_oLBServerVector.erase(oLBIter);
        m_oLBServerVector.push_back(stServerAddr);
        apr_thread_mutex_unlock(m_pstMutex);
    }
    if(iRet != APR_SUCCESS) {
        return iRet;
    }

(note:一个变量作为一个类的成员变量时,是多个线程共享的。作为临时变量,则是每个线程一份。)

这段代码的加锁有问题。 问题:当两个线程都执行到 erase 的时候,vector被移动了两次。

解决方法一:把 m_iQueryFromServerTCP()函数一起加锁,但是这样的话,锁太大,不建议采用。

解决方法二:在 erase 之前,先判断下当前的iter指向的是不是和之前取出来的一样。 一样的话就移动, 不一样的话就不移动。

解决方法三:把 iter 作为一个成员变量,这样就所有的线程都共享, 在构造函数中初始化 iter = m_oLBServerVector.begin(); 然后每次都取出 iter 当前指向的值, 失败的时候就把 iter 向后移动一格。 (这种方法相当于是一个ring,所有线程共享一个指针。)

解决方法四:用一个ring,每个线程都有一个自己的移动指针。

解决方法三 的代码如下:

    apr_thread_mutex_lock(m_pstMutex);
    apr_int32_t iMaxTryTime = m_oLBServerVector.size();
    apr_thread_mutex_unlock(m_pstMutex);
    while ( iMaxTryTime-- > 0 )
    {
        char acServerIPAddr[MAX_IPADDRESS_LENGTH] = {0};
        apr_uint32_t uiServerPort;

        apr_thread_mutex_lock(m_pstMutex);
        strcpy(acServerIPAddr, m_oLBIter->m_acServerIPAddr);
        uiServerPort = m_oLBIter->m_uiServerPort;
        apr_thread_mutex_unlock(m_pstMutex);

        iRet = m_iQueryFromServerTCP(
                acServerIPAddr,
                uiServerPort,
                acSendMsgBuf,
                usSendMsgLen,
                acRecvMsgBuf,
                &usRecvMsgLen,
                &ucMsgType);
        if(APR_SUCCESS == iRet) {
            break;
        }

        apr_thread_mutex_lock(m_pstMutex);
        if(strcmp(acServerIPAddr, m_oLBIter->m_acServerIPAddr) == 0 &&
           uiServerPort == m_oLBIter->m_uiServerPort)
        {
            m_oLBIter++;
            if(m_oLBIter == m_oLBServerVector.end()) {
                m_oLBIter = m_oLBServerVector.begin();
            }
        }
        apr_thread_mutex_unlock(m_pstMutex);
    }
    if(iRet != APR_SUCCESS) {
        return iRet;
    }

weixingongzhonghao

Similar Posts

Comments