我正在查看一个简单的类,我必须管理关键部分和锁,我想用测试用例来解决这个问题。这是否有意义,以及如何去做?这很困难,因为验证类工作的唯一方法是设置非常复杂的线程场景,即使这样,也没有一种好方法可以测试Win32中关键部分的泄漏。有没有更直接的方法来确保它正常工作?
以下是代码:
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) {} ;
}}
答案 0 :(得分:4)
以下是三个选项,我个人赞成最后一个......
然而....
我怀疑你的设计选择。首先,课堂上发生了太多事情(恕我直言)。引用计数和锁定是正交的。我将它们分开,以便我有一个简单的类进行关键部分管理然后构建它我发现我真的需要引用计数...其次是引用计数和锁定函数的设计;而不是返回一个在其dtor中释放锁的对象,为什么不简单地在堆栈上创建一个对象来创建一个范围锁。这将消除大部分复杂性。事实上,你最终可能会得到一个简单的关键部分类:
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);
}
这符合我对这种代码的想法,这种代码很容易引人注目而不是引入复杂的测试...
然后你可以有一个范围锁定类,如:
CCriticalSection::Owner::Owner(
ICriticalSection &crit)
: m_crit(crit)
{
m_crit.Enter();
}
CCriticalSection::Owner::~Owner()
{
m_crit.Leave();
}
你会像这样使用它
void MyClass::DoThing()
{
ICriticalSection::Owner lock(m_criticalSection);
// We're locked whilst 'lock' is in scope...
}
当然我的代码没有使用TryEnter()
或做任何复杂的事情,但没有什么可以阻止你的简单RAII类做更多事情;虽然,恕我直言,我认为实际上很少需要TryEnter()
。