Frage

Ich freue mich auf eine einfache Klasse I kritische Abschnitte und Sperren zu verwalten haben, und ich möchte diese Fälle mit Test decken. Macht das Sinn, und wie würde man gehen über es zu tun? Es ist schwierig, weil der einzige Weg, um die Klasse arbeitet, um zu überprüfen, um Setup sehr komplizierte Einfädeln Szenarien ist, und selbst dann gibt es keine guten Weg für ein Leck von einem kritischen Abschnitt in Win32 zu testen. Gibt es einen direkteren Weg, um sicherzustellen, dass es funktioniert richtig?

Hier ist der 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(&sectionStructure); };
    void Enter() { EnterCriticalSection(&sectionStructure); };
    bool TryEnter() { if (TryEnterCriticalSection(&sectionStructure)) return true; else return false; };
    void Leave() { LeaveCriticalSection(&sectionStructure); };
public:
    ~CriticalSectionImpl() { DeleteCriticalSection(&sectionStructure); };
};

void CriticalSection::Enter() { impl->Enter(); };
bool CriticalSection::TryEnter() { return impl->TryEnter(); };
void CriticalSection::Leave() { impl->Leave(); };
CriticalSection::CriticalSection() : impl(new CriticalSectionImpl) {} ;

}}
War es hilfreich?

Lösung

Hier sind drei Optionen und persönlich favorisieren ich die letzten ...

Allerdings ....

Ich bin zweifelhaft Ihre Designwahl. Zum einen ist es zu viel in der Klasse (IMHO) geht. Die Referenzzählung und die Verriegelungs sind orthogonal. Ich würde sie auseinandergerissen, so dass ich eine einfache Klasse hatte die kritischen Abschnitt Management tat und dann darauf gebaut Ich fand ich wirklich Referenzzählung benötigt ... Zweitens gibt es die Referenzzählung und das Design Ihrer Sperrfunktionen; anstatt ein Objekt zurückkehrt, der die Sperre in seiner dtor veröffentlicht warum nicht einfach ein Objekt, das Sie auf dem Stapel erstellen scoped Sperre zu erstellen. Dies würde viel von der Komplexität entfernen. In der Tat könnte man mit einem kritischen Abschnitt Klasse am Ende, die so einfach wie das ist:

CCriticalSection::CCriticalSection()
{
   ::InitializeCriticalSection(&m_crit);
}

CCriticalSection::~CCriticalSection()
{
   ::DeleteCriticalSection(&m_crit);
}

#if(_WIN32_WINNT >= 0x0400)
bool CCriticalSection::TryEnter()
{
   return ToBool(::TryEnterCriticalSection(&m_crit));
}
#endif

void CCriticalSection::Enter()
{
   ::EnterCriticalSection(&m_crit);
}

void CCriticalSection::Leave()
{
   ::LeaveCriticalSection(&m_crit);
}

Welche paßt zu meiner Vorstellung von dieser Art von Code einfach genug zu sein Augapfel, anstatt der Einführung komplexen Tests ...

Sie könnten dann eine scoped Sperrklasse haben wie:

CCriticalSection::Owner::Owner(
   ICriticalSection &crit)
   : m_crit(crit)
{
   m_crit.Enter();
}

CCriticalSection::Owner::~Owner()
{
   m_crit.Leave();
}

Sie würden es so verwenden

void MyClass::DoThing()
{
   ICriticalSection::Owner lock(m_criticalSection);

   // We're locked whilst 'lock' is in scope...
}

Natürlich mein Code nicht TryEnter() verwenden oder etwas komplexer zu tun, aber es gibt nichts, Ihre einfache RAII-Klassen zu stoppen mehr zu tun; aber meiner Meinung nach, ich denke TryEnter() eigentlich sehr selten erforderlich ist.

scroll top