[EDIT] Does anyone know how to get a class member container that require lock from outside properly? Writing to a class member can be done as below if critical section is used for locking.
EnterCriticalSection(&m_cs);
// write
LeaveCriticalSection(&m_cs);
However, if it is necessary to lookup this container to find data from current data that the container holds. What I could think of was defining Lock, Unlock member function for a class containing the container. And calling them before and after Get.
void Lock(){ EnterCriticalSection(&m_cs); }
std::map<unsigned long long, CObject>& Get() { return m_mapObject; }
void Unlock(){ LeaveCriticalSection(&m_cs); }
This doesn't seem right as far as it is open to error.
What I'm looking for seems to be collaboration of these.
Class variables: public access read-only, but private access read/write
Return locked resource from class with automatic unlocking
Perhaps I'm having difficulty in finding relevant keyword to search.
Below is a small example code for detail.
#include <iostream>
#include <Windows.h>
#include <map>
class CObject
{
private:
int m_nData;
public:
CObject()
: m_nData(0)
{
}
~CObject()
{
}
void Set(const int _nData) { m_nData = _nData; }
int Get() { return m_nData; }
};
class CObjectManager
{
private:
CRITICAL_SECTION m_cs;
std::map<unsigned long long, CObject> m_mapObject;
public:
CObjectManager()
: m_cs{}
, m_mapObject{}
{
InitializeCriticalSection(&m_cs);
}
~CObjectManager()
{
DeleteCriticalSection(&m_cs);
}
bool Add(const unsigned long long _key, const CObject _object)
{
bool bReturn = false;
EnterCriticalSection(&m_cs);
if (m_mapObject.find(_key) == m_mapObject.end())
{
m_mapObject.insert(std::pair<unsigned long long, CObject>(_key, _object));
bReturn = true;
}
LeaveCriticalSection(&m_cs);
return bReturn;
}
bool Delete(const unsigned long long _key)
{
bool bReturn = false;
EnterCriticalSection(&m_cs);
std::map<unsigned long long, CObject>::iterator iter = m_mapObject.find(_key);
if (iter != m_mapObject.end())
{
m_mapObject.erase(iter);
bReturn = true;
}
LeaveCriticalSection(&m_cs);
return bReturn;
}
void Lock(){ EnterCriticalSection(&m_cs); }
std::map<unsigned long long, CObject>& Get() { return m_mapObject; }
void Unlock(){ LeaveCriticalSection(&m_cs); }
};
void DoSomething(CObject* _pObject)
{
int a = 10;
}
CObjectManager objectManager{};
DWORD Thread(LPVOID _pParam)
{
for (unsigned long long i = 0ull; i < 100000ull; i)
{
CObject object{};
object.Set(i);
objectManager.Add(i, object);
}
return 0;
}
int main()
{
CObject object0;
object0.Set(1);
CObject object1;
object1.Set(2);
bool b = objectManager.Add(3ull, object0);
bool b1 = objectManager.Add(3ull, object1);
bool b2 = objectManager.Add(4ull, object1);
bool b3 = objectManager.Delete(3ull);
CreateThread(nullptr, 0, &Thread, nullptr, 0, nullptr);
Sleep(0);
// Need to get current COject map of CObjectManager
CObject object2{};
std::map<unsigned long long, CObject>::iterator iter;
while (true)
{
objectManager.Lock();
std::map<unsigned long long, CObject> mapObject = objectManager.Get();
iter = mapObject.find(90000ull);
if (iter != mapObject.end())
{
object2.Set(iter->second.Get());
objectManager.Unlock();
break;
}
objectManager.Unlock();
}
DoSomething(&object2);
Sleep(2000);
return 0;
}
Any comment or answer will be appreciated.
CodePudding user response:
If what concerns you is caller potentially missing lock/unlock calls, then a RAII pattern might be of help:
class CObjectManager
{
private:
CRITICAL_SECTION m_cs;
std::map<unsigned long long, CObject> m_mapObject;
public:
CObjectManager()
: m_cs{}
, m_mapObject{}
{
InitializeCriticalSection(&m_cs);
}
~CObjectManager()
{
DeleteCriticalSection(&m_cs);
}
auto LockAndGet()
{
EnterCriticalSection(&m_cs);
struct LockAndGetResult
{
private:
CRITICAL_SECTION& m_cs;
public:
std::map<unsigned long long, CObject> m_mapObject;
LockAndGetResult(CRITICAL_SECTION& cs, std::map<unsigned long long, CObject>& mapObject) : m_cs(cs), m_mapObject(mapObject) {}
~LockAndGetResult() { LeaveCriticalSection(&m_cs); }
};
return LockAndGetResult(m_cs, m_mapObject);
}
};
// usage:
CObjectManager co;
{
auto maplock = co.LockAndGet();
doSomethingWith(maplock.m_mapObject);
} // maplock dtor releases lock