Hello all :)
I'm looking at a simple class I have to manage critical sections and locks, and I'd like to cover this with test cases. Does this make sense, and how would one go about doing it? It's difficult because the only way to verify the class works is to setup very complicated threading scenarios, and even then there's not a good way to test for a leak of a Critical Section in Win32. Is there a more direct way to make sure it's working correctly?
Here's the code:
CriticalSection.hpp:
#pragma once
#include <windows.h>
namespace WindowsAPI { namespace Threading {
class CriticalSection;
class CriticalLock
{
std::size_t *instanceCount;
CRITICAL_SECTION * criticalStructure;
bool lockValid;
friend class CriticalSection;
CriticalLock(std::size_t *, CRITICAL_SECTION *, bool);
public:
bool IsValid() { return lockValid; };
void Unlock();
~CriticalLock() { Unlock(); };
};
class CriticalSection
{
std::size_t *instanceCount;
CRITICAL_SECTION * criticalStructure;
public:
CriticalSection();
CriticalSection(const CriticalSection&);
CriticalSection& operator=(const CriticalSection&);
CriticalSection& swap(CriticalSection&);
~CriticalSection();
CriticalLock Enter();
CriticalLock TryEnter();
};
}}
CriticalSection.cpp:
#include "CriticalSection.hpp"
namespace WindowsAPI { namespace Threading {
CriticalSection::CriticalSection()
{
criticalStructure = new CRITICAL_SECTION;
instanceCount = new std::size_t;
*instanceCount = 1;
InitializeCriticalSection(criticalStructure);
}
CriticalSection::CriticalSection(const CriticalSection& other)
{
criticalStructure = other.criticalStructure;
instanceCount = other.instanceCount;
instanceCount++;
}
CriticalSection& CriticalSection::operator=(const CriticalSection& other)
{
CriticalSection copyOfOther(other);
swap(copyOfOther);
return *this;
}
CriticalSection& CriticalSection::swap(CriticalSection& other)
{
std::swap(other.instanceCount, instanceCount);
std::swap(other.criticalStructure, other.criticalStructure);
return *this;
}
CriticalSection::~CriticalSection()
{
if (!--(*instanceCount))
{
DeleteCriticalSection(criticalStructure);
delete criticalStructure;
delete instanceCount;
}
}
CriticalLock CriticalSection::Enter()
{
EnterCriticalSection(criticalStructure);
(*instanceCount)++;
return CriticalLock(instanceCount, criticalStructure, true);
}
CriticalLock CriticalSection::TryEnter()
{
bool lockAquired;
if (TryEnterCriticalSection(criticalStructure))
{
(*instanceCount)++;
lockAquired = true;
}
else
lockAquired = false;
return CriticalLock(instanceCount, criticalStructure, lockAquired);
}
void CriticalLock::Unlock()
{
if (!lockValid)
return;
LeaveCriticalSection(criticalStructure);
lockValid = false;
if (!--(*instanceCount))
{
DeleteCriticalSection(criticalStructure);
delete criticalStructure;
delete instanceCount;
}
}
}}