forked from organicmaps/organicmaps
moved FenceManager to base library and added tests for it.
This commit is contained in:
parent
c8d6ba21db
commit
c260a4a9df
12 changed files with 251 additions and 132 deletions
|
@ -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 \
|
||||
|
|
|
@ -33,7 +33,9 @@ SOURCES += \
|
|||
threaded_list_test.cpp \
|
||||
condition_test.cpp \
|
||||
containers_test.cpp \
|
||||
fence_manager_test.cpp
|
||||
|
||||
|
||||
HEADERS +=
|
||||
|
||||
|
||||
|
|
95
base/base_tests/fence_manager_test.cpp
Normal file
95
base/base_tests/fence_manager_test.cpp
Normal 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, ())
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
90
base/fence_manager.cpp
Normal 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
26
base/fence_manager.hpp
Normal 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);
|
||||
};
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "fence_manager.hpp"
|
||||
#include "../base/fence_manager.hpp"
|
||||
|
||||
#include "../base/threaded_list.hpp"
|
||||
#include "../base/mutex.hpp"
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue