Je regarde une classe simple Je dois gérer des sections critiques et des verrous, et je voudrais couvrir cela avec des cas de test. Est-ce que cela a du sens, et comment on s'y prendrait? C'est difficile parce que la seule façon de vérifier le fonctionnement de la classe est de mettre en place des scénarios de threads très compliqués, et même là, il n'y a pas de moyen de tester la fuite d'une section critique dans Win32. Existe-t-il un moyen plus direct de s'assurer que cela fonctionne correctement?Tests unitaires Refcounted Section Critique Classe
Voici le code:
CriticalSection.hpp:
#pragma once
#include <windows.h>
#include <boost/shared_ptr.hpp>
namespace WindowsAPI { namespace Threading {
class CriticalSectionImpl;
class CriticalLock;
class CriticalAttemptedLock;
class CriticalSection
{
friend class CriticalLock;
friend class CriticalAttemptedLock;
boost::shared_ptr<CriticalSectionImpl> impl;
void Enter();
bool TryEnter();
void Leave();
public:
CriticalSection();
};
class CriticalLock
{
CriticalSection &ref;
public:
CriticalLock(CriticalSection& sectionToLock) : ref(sectionToLock) { ref.Enter(); };
~CriticalLock() { ref.Leave(); };
};
class CriticalAttemptedLock
{
CriticalSection &ref;
bool valid;
public:
CriticalAttemptedLock(CriticalSection& sectionToLock) : ref(sectionToLock), valid(ref.TryEnter()) {};
bool LockHeld() { return valid; };
~CriticalAttemptedLock() { if (valid) ref.Leave(); };
};
}}
CriticalSection.cpp:
#include "CriticalSection.hpp"
namespace WindowsAPI { namespace Threading {
class CriticalSectionImpl
{
friend class CriticalSection;
CRITICAL_SECTION sectionStructure;
CriticalSectionImpl() { InitializeCriticalSection(§ionStructure); };
void Enter() { EnterCriticalSection(§ionStructure); };
bool TryEnter() { if (TryEnterCriticalSection(§ionStructure)) return true; else return false; };
void Leave() { LeaveCriticalSection(§ionStructure); };
public:
~CriticalSectionImpl() { DeleteCriticalSection(§ionStructure); };
};
void CriticalSection::Enter() { impl->Enter(); };
bool CriticalSection::TryEnter() { return impl->TryEnter(); };
void CriticalSection::Leave() { impl->Leave(); };
CriticalSection::CriticalSection() : impl(new CriticalSectionImpl) {} ;
}}
Quelques problèmes avec ceci. #1. Les structures CRITICAL_SECTION ne peuvent pas être déplacées ou copiées. C'est la raison pour laquelle le refcounting en premier lieu. Par conséquent, une certaine forme de recomptage est essentielle car je ne veux pas que les clients aient à se soucier de la gestion de la mémoire de la classe. # 2: J'aime beaucoup mieux la manipulation de la serrure. Merci beaucoup :) # 3: Je vais regarder en quelque sorte se moquant des fonctions de l'API - ce qui est ironique parce que la moitié du point de l'objet section critique est de pouvoir tester le code en l'utilisant. –
Je n'ai jamais trouvé # 1 d'être un problème; c'est peut-être la façon dont j'utilise mes serrures. J'ajoute simplement une instance de 'CCriticalSection' à une classe qui doit être capable de verrouiller des zones de lui-même, puis d'utiliser la classe RAII 'owner' pour gérer la durée de vie du verrou. Pour les objets qui ont leurs propres verrous j'ai rarement une copie ctor ou une opération d'affectation; ça n'a jamais de sens, donc je n'ai pas de problème et je n'ai pas besoin du ref ... –
Je suppose que je pourrais juste rendre l'objet section critique non-discutable mais pour l'instant je suis dans un scénario où j'ai vraiment besoin l'objet section critique à avoir la sémantique "' shared_ptr' ". Si les sections critiques n'avaient pas besoin de démontage spécial, j'utiliserais simplement 'shared_ptr' et j'aurais fini avec, mais malheureusement ils le font :( –