Ваше обновление не лучше. Если вы хотите сделать это в стиле RAII, вам нужно работать немного усерднее. Ключ заключается в том, что вам необходимо отделить объект критической секции, который статически размещен, и блокировку, которая является локальной для всех блоков, которые нуждаются в защите.
Следующая фраза взята из Джонатан Доддс , но это классический образец.
class CriticalSection
{
public:
CriticalSection()
{ ::InitializeCriticalSection(&m_rep); }
~CriticalSection()
{ ::DeleteCriticalSection(&m_rep); }
void Enter()
{ ::EnterCriticalSection(&m_rep); }
void Leave()
{ ::LeaveCriticalSection(&m_rep); }
private:
// copy ops are private to prevent copying
CriticalSection(const CriticalSection&);
CriticalSection& operator=(const CriticalSection&);
CRITICAL_SECTION m_rep;
};
Хотя вы могли бы сделать это с наследованием CRITICAL_SECTION, я считаю, что инкапсуляция является более подходящей.
Далее определена блокировка:
class CSLock
{
public:
CSLock(CriticalSection& a_section)
: m_section(a_section) { m_section.Enter(); }
~CSLock()
{ m_section.Leave(); }
private:
// copy ops are private to prevent copying
CSLock(const CSLock&);
CSLock& operator=(const CSLock&);
CriticalSection& m_section;
};
Наконец, пример использования:
class Example
{
public:
bool Process( … );
…
private:
CriticalSection m_criticalsection;
…
};
bool Example::Process( … )
{
CSLock lock(m_critsection);
// do some stuff
…
}
Дело в том, что существует один экземпляр критического раздела, общий для всех потоков. Это то, что заставляет работать критический раздел.
В контрапункте может быть много случаев CSLock
, взятых в одном и том же критическом разделе, в одновременном существовании. Это позволяет методу Process()
вызываться многими потоками, но его код сериализуется в течение времени жизни экземпляра CSLock
, взятого в одном общем критическом разделе.