Ok,let me explain it in details
1 I have to maintain a collection for all the clients data,such as
1 2 3 4 5 6
|
struct CLIENT_DATA
{
std::string m_strIp;
int m_nOnlineTime;
int m_nCredits;
};
|
2 the client data update(by a timer for example) and the socket are in different thread
so If I use a map
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
|
bool Connect(std::string strIp)
{
boost::lock_guard<boost::mutex> lock(m_lock);
CLIENT_DATA* pData = new CLIENT_DATA;
pData->m_nOnlineTime = 0;
pData->m_strIp = strIp;
m_mapClients.push_back(strIp,pData);
return true;
}
void Disconnect(std::string strIp);
{
boost::lock_guard<boost::mutex> lock(m_lock);
std::map<std::string,CLIENT_DATA*>::iterator iter = m_mapClients.find(strIp);
if(iter != m_mapClients.end())
return;
CLIENT_DATA* pClientData = m_mapClients[strIp];
if(pClientData != NULL)
{
delete pClientData;
pClientData = NULL;
}
m_mapClients.erase(iter);
}
bool UpdateOnlineTime(std::string strIp)
{
boost::lock_guard<boost::mutex> lock(m_lock);
std::map<std::string,CLIENT_DATA*>::iterator iter = m_mapClients.find(strIp);
if(iter != m_mapClients.end())
return false;
CLIENT_DATA* pClientData = m_mapClients[strIp];
if(pClientData == NULL)
return false;
pClientData->m_nOnlineTime += 10;
return true;
}
|
I have to lock the map use the same mutex in connect,disconnect,updateonlinetime
if I use a array
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
|
void PrepareIds()
{
for(int i=0;i<10240;i++)
m_vecAvailableIds.push_back(i);
}
int FetchId()
{
boost::lock_guard<boost::mutex> lock(m_lock);
if(m_vecAvailableIds.size()<=0)
return -1;
int nId = m_vecAvailableIds.back();
m_vecAvailableIds.pop_front();
return nId;
}
int ReturnId(int nId)
{
boost::lock_guard<boost::mutex> lock(m_lock);
m_vecAvailableIds.push_back(nId);
}
bool Connected(std::string strIp)
{
int nNewId = FetchId();
if(nNewId == -1)
return false;
CLIENT_DATA* pData = m_arrClients[nNewId];
boost::lock_guard<boost::mutex> lock(pData->m_mutex_lock);
pData->m_bInUse = true;
pData->m_nOnlineTime = 0;
pData->m_strIP = strIp;
}
bool Disconnected(int nClientId)
{
Assert(nClientId>=0 && nClientId<10240);
CLIENT_DATA* pData = m_arrClients[nClientId];
boost::lock_guard<boost::mutex> lock(pData->m_mutex_lock);
pData->m_bInUse = false;
ReturnId(nClientId);
return true;
}
|
Now,the UpdateOnlineTime function and the CLIENT_DATA structure are changed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
struct CLIENT_DATA
{
std::string m_strIp;
int m_nOnlineTime;
int m_nCredits;
bool m_bInUse;
boost::mutex m_mutex_data;
};
bool UpdateOnlineTime(int nClientId)
{
Assert(nClientId>=0 && nClientId<10240);
CLIENT_DATA* pData = m_arrClients[nClientId];
boost::lock_guard<boost::mutex> lock(pData->m_mutex_lock);
if(! pClientData->m_bIsInUse)
return false;
pClientData->m_nOnlineTime += 10;
return true;
}
|
There is only need to lock one CLIENT_DATA in case we may update the m_nCredits in some other place.
Now there are two kinds of mutex,one for Ids,one for each CLIENT_DATA
the most important point is when I iterate all the client datas
if I use a map:
1 2 3 4 5 6 7 8 9
|
UpdateClients()
{
boost::lock_guard<boost::mutex> lock(m_lock); //lock the whole map
for(int i=0;i<m_mapClients.size();i++)
{
Update();
}
}
|
if I use an array
1 2 3 4 5 6 7 8 9
|
UpdateClients()
{
//there is no need to lock
for(int i=0;i<m_arrClients.size();i++)
{
Update();
}
}
|
if the map size if very large,such as 10240;
lock the whole map would block the connect or disconnect operation.