Я смотрю на простой класс, я должен управлять критическими разделами и замками, и я хотел бы осветить это тестовыми примерами. Имеет ли это смысл, и как это сделать? Это сложно, потому что единственный способ проверить работу класса - установить очень сложные сценарии потоковой передачи, и даже тогда нет хорошего способа протестировать утечку критической секции в 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) {} ;
}}
Немногие проблемы с этим. # 1. Структуры CRITICAL_SECTION не могут быть перемещены или скопированы. В этом причина пересчета в первую очередь. Поэтому некоторая форма пересчета здесь важна, потому что я не хочу, чтобы клиентам приходилось беспокоиться о управлении памятью класса. # 2: Мне нравится, как ваше управление блокировкой намного лучше. Большое спасибо :) # 3: Я собираюсь взглянуть на некоторые издевательства над функциями API, что иронично, потому что половина точки объекта критического раздела должна быть в состоянии проверить код, используя его. –
Я никогда не встречал # 1, чтобы быть проблемой; возможно, именно так я использую свои блокировки. Я просто добавляю экземпляр 'CCriticalSection' к классу, который должен иметь возможность блокировать области, а затем использовать класс владельца RAII для управления временем жизни блокировки. Для объектов, у которых есть свои блокировки, я редко имею копию ctor или присваивание op; это просто никогда не имеет смысла, поэтому у меня нет проблем и мне не нужен счетчик ссылок ... –
Я полагаю, что я мог бы просто сделать объект критического раздела не подлежащим копированию, но пока я в сценарии, где мне действительно нужно объект критического раздела имеет семантику «shared_ptr». Если критические разделы не нуждались в специальном разрыве, я бы просто использовал 'shared_ptr' и делал с ним, но, к сожалению, они делают :( –