moved FenceManager to base library and added tests for it.

This commit is contained in:
rachytski 2012-01-02 22:19:37 +04:00 committed by Alex Zolotarev
parent c8d6ba21db
commit c260a4a9df
12 changed files with 251 additions and 132 deletions

View file

@ -25,6 +25,7 @@ SOURCES += \
exception.cpp \
threaded_container.cpp \
resource_pool.cpp \
fence_manager.cpp \
HEADERS += \
SRC_FIRST.hpp \
@ -71,3 +72,4 @@ HEADERS += \
limited_priority_queue.hpp \
threaded_priority_queue.hpp \
std_serialization.hpp \
fence_manager.hpp \

View file

@ -33,7 +33,9 @@ SOURCES += \
threaded_list_test.cpp \
condition_test.cpp \
containers_test.cpp \
fence_manager_test.cpp
HEADERS +=

View file

@ -0,0 +1,95 @@
#include "../../testing/testing.hpp"
#include "../commands_queue.hpp"
#include "../fence_manager.hpp"
#include "../../std/bind.hpp"
void add_int(core::CommandsQueue::Environment const & env,
int fenceID,
FenceManager & fenceManager,
int & i,
int a,
int ms)
{
threads::Sleep(ms);
if (env.isCancelled())
return;
i += a;
LOG(LINFO, ("add_int result:", i));
fenceManager.signalFence(fenceID);
}
void join_mul_int(core::CommandsQueue::Environment const & env,
int fenceID,
FenceManager & fenceManager,
int & i,
int b,
int ms)
{
threads::Sleep(ms);
fenceManager.joinFence(fenceID);
i *= b;
LOG(LINFO, ("join_mul_int result: ", i));
}
UNIT_TEST(FenceManager_SimpleFence)
{
FenceManager fenceManager(3);
core::CommandsQueue queue(2);
int i = 3;
queue.Start();
int fenceID = fenceManager.insertFence();
queue.AddCommand(bind(&add_int, _1, fenceID, ref(fenceManager), ref(i), 5, 500));
queue.AddCommand(bind(&join_mul_int, _1, fenceID, ref(fenceManager), ref(i), 3, 1));
queue.Join();
queue.Cancel();
TEST(i == 24, ());
}
UNIT_TEST(FenceManager_JoinAlreadySignalled)
{
FenceManager fenceManager(3);
core::CommandsQueue queue(2);
int i = 3;
queue.Start();
int fenceID = fenceManager.insertFence();
queue.AddCommand(bind(&add_int, _1, fenceID, ref(fenceManager), ref(i), 5, 1));
queue.AddCommand(bind(&join_mul_int, _1, fenceID, ref(fenceManager), ref(i), 3, 500));
queue.Join();
queue.Cancel();
TEST(i == 24, ());
}
UNIT_TEST(FenceManager_SignalAlreadySignalled)
{
FenceManager fenceManager(3);
core::CommandsQueue queue(2);
int i = 3;
queue.Start();
int fenceID = fenceManager.insertFence();
fenceManager.signalFence(fenceID);
queue.AddCommand(bind(&add_int, _1, fenceID, ref(fenceManager), ref(i), 5, 1));
queue.AddCommand(bind(&join_mul_int, _1, fenceID, ref(fenceManager), ref(i), 3, 500));
queue.Join();
queue.Cancel();
TEST(i == 24, ())
}

View file

@ -40,7 +40,7 @@ namespace core
threads::ConditionGuard g(*m_cond.get());
m_waitCount++;
if (!m_isCompleted)
m_cond->Wait();
g.Wait();
}
else
LOG(LERROR, ("command isn't waitable"));
@ -54,7 +54,7 @@ namespace core
m_isCompleted = true;
CHECK(m_waitCount < 2, ("only one thread could wait for the queued command"));
if (m_waitCount)
m_cond->Signal(true);
g.Signal(true);
}
}
@ -215,14 +215,14 @@ namespace core
--m_activeCommands;
if (m_activeCommands == 0)
m_cond.Signal();
g.Signal();
}
void CommandsQueue::Join()
{
threads::ConditionGuard g(m_cond);
if (m_activeCommands != 0)
m_cond.Wait();
while (m_activeCommands != 0)
g.Wait();
}
void CommandsQueue::Clear()

View file

@ -7,3 +7,28 @@
#else
#include "condition_posix.cpp"
#endif
namespace threads
{
ConditionGuard::ConditionGuard(Condition & condition)
: m_Condition(condition)
{
m_Condition.Lock();
}
ConditionGuard::~ConditionGuard()
{
m_Condition.Unlock();
}
void ConditionGuard::Wait()
{
m_Condition.Wait();
}
void ConditionGuard::Signal(bool broadcast)
{
m_Condition.Signal(broadcast);
}
}

View file

@ -28,13 +28,12 @@ namespace threads
/// ScopeGuard wrapper around mutex
class ConditionGuard
{
public:
ConditionGuard(Condition & condition)
: m_Condition(condition) { m_Condition.Lock(); }
~ConditionGuard() { m_Condition.Unlock(); }
void Wait() { m_Condition.Wait(); }
void Signal(bool broadcast = false) { m_Condition.Signal(broadcast); }
private:
Condition & m_Condition;
public:
ConditionGuard(Condition & condition);
~ConditionGuard();
void Wait();
void Signal(bool broadcast = false);
};
}

90
base/fence_manager.cpp Normal file
View file

@ -0,0 +1,90 @@
#include "fence_manager.hpp"
#include "../base/assert.hpp"
#include "../base/logging.hpp"
FenceManager::FenceManager(int conditionPoolSize)
: m_currentFence(0)
{
m_conditionPool.resize(conditionPoolSize);
for (unsigned i = 0; i < m_conditionPool.size(); ++i)
m_conditionPool[i] = new threads::Condition();
}
FenceManager::~FenceManager()
{
for (map<int, threads::Condition*>::const_iterator it = m_activeFences.begin();
it != m_activeFences.end();
++it)
{
it->second->Signal();
delete it->second;
}
for (unsigned i = 0; i < m_conditionPool.size(); ++i)
{
delete m_conditionPool[i];
}
}
int FenceManager::insertFence()
{
threads::MutexGuard g(m_mutex);
if (m_conditionPool.empty())
return -1;
threads::Condition * cond = m_conditionPool.back();
m_conditionPool.pop_back();
int id = m_currentFence++;
m_activeFences[id] = cond;
return id;
}
void FenceManager::signalFence(int id)
{
threads::MutexGuard g(m_mutex);
map<int, threads::Condition*>::iterator it = m_activeFences.find(id);
if (it == m_activeFences.end())
{
LOG(LWARNING, ("fence with id", id, "has been already signalled or hasn't been installed yet"));
return;
}
threads::Condition * cond = it->second;
/// signalling to all waiting fences
cond->Signal(true);
/// erasing fence from active fences
m_activeFences.erase(it);
/// returning condition to the pool
m_conditionPool.push_back(cond);
}
void FenceManager::joinFence(int id)
{
threads::Condition * cond = 0;
{
threads::MutexGuard g(m_mutex);
map<int, threads::Condition*>::iterator it = m_activeFences.find(id);
if (it == m_activeFences.end())
{
LOG(LWARNING, ("fence with id", id, "has been already reached in the past or hasn't been installed yet"));
return;
}
cond = it->second;
}
threads::ConditionGuard g(*cond);
g.Wait();
}

26
base/fence_manager.hpp Normal file
View file

@ -0,0 +1,26 @@
#pragma once
#include "../base/condition.hpp"
#include "../base/mutex.hpp"
#include "../std/map.hpp"
#include "../std/vector.hpp"
class FenceManager
{
private:
threads::Mutex m_mutex;
vector<threads::Condition *> m_conditionPool;
map<int, threads::Condition *> m_activeFences;
int m_currentFence;
public:
FenceManager(int conditionPoolSize);
~FenceManager();
int insertFence();
void joinFence(int id);
void signalFence(int id);
};

View file

@ -1,89 +0,0 @@
#include "fence_manager.hpp"
#include "../base/assert.hpp"
#include "../base/logging.hpp"
namespace yg
{
FenceManager::FenceManager(int conditionPoolSize)
: m_currentFence(0)
{
m_conditionPool.resize(conditionPoolSize);
for (unsigned i = 0; i < m_conditionPool.size(); ++i)
m_conditionPool[i] = new threads::Condition();
}
FenceManager::~FenceManager()
{
for (map<int, threads::Condition*>::const_iterator it = m_activeFences.begin();
it != m_activeFences.end();
++it)
{
it->second->Signal(true);
delete it->second;
}
for (unsigned i = 0; i < m_conditionPool.size(); ++i)
{
delete m_conditionPool[i];
}
}
int FenceManager::insertFence()
{
threads::MutexGuard g(m_mutex);
if (m_conditionPool.empty())
return -1;
threads::Condition * cond = m_conditionPool.back();
m_conditionPool.pop_back();
int id = m_currentFence++;
m_activeFences[id] = cond;
return id;
}
void FenceManager::signalFence(int id)
{
threads::MutexGuard g(m_mutex);
map<int, threads::Condition*>::iterator it = m_activeFences.find(id);
CHECK(it != m_activeFences.end(), ("using singalFence twice for the same id is error"));
threads::Condition * cond = it->second;
/// signalling to all waiting fences
cond->Signal(true);
/// erasing fence from active fences
m_activeFences.erase(it);
/// returning condition to the pool
m_conditionPool.push_back(cond);
}
void FenceManager::joinFence(int id)
{
threads::Condition * cond = 0;
{
threads::MutexGuard g(m_mutex);
map<int, threads::Condition*>::iterator it = m_activeFences.find(id);
if (it == m_activeFences.end())
{
LOG(LINFO, ("fence has been reached in the past or haven't been installed yet"));
return;
}
cond = it->second;
}
threads::ConditionGuard g(*cond);
g.Wait();
}
}

View file

@ -1,29 +0,0 @@
#pragma once
#include "../base/condition.hpp"
#include "../base/mutex.hpp"
#include "../std/map.hpp"
#include "../std/vector.hpp"
namespace yg
{
class FenceManager
{
private:
threads::Mutex m_mutex;
vector<threads::Condition *> m_conditionPool;
map<int, threads::Condition *> m_activeFences;
int m_currentFence;
public:
FenceManager(int conditionPoolSize);
~FenceManager();
int insertFence();
void joinFence(int id);
void signalFence(int id);
};
}

View file

@ -1,6 +1,6 @@
#pragma once
#include "fence_manager.hpp"
#include "../base/fence_manager.hpp"
#include "../base/threaded_list.hpp"
#include "../base/mutex.hpp"

View file

@ -63,7 +63,6 @@ SOURCES += \
glyph_style.cpp \
circle_element.cpp \
packets_queue.cpp \
fence_manager.cpp
HEADERS += \
internal/opengl.hpp \
@ -120,7 +119,6 @@ HEADERS += \
agg_traits.hpp \
circle_element.hpp \
packets_queue.hpp \
fence_manager.hpp
win32* {
SOURCES += internal/opengl_win32.cpp