Make event listeners threaded.
continuous-integration/drone/push Build is failing Details

Signed-off-by: Deukhoofd <Deukhoofd@gmail.com>
This commit is contained in:
Deukhoofd 2020-08-07 12:20:59 +02:00
parent 665227a033
commit 208bb097dd
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
4 changed files with 37 additions and 4 deletions

View File

@ -14,6 +14,9 @@ option(STATICC "Whether gcc and stdc++ should be linked statically to the librar
include(CmakeConanSetup.cmake) include(CmakeConanSetup.cmake)
SetupConan() SetupConan()
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
# Set whether we want a static or shared library. # Set whether we want a static or shared library.
set(LIBTYPE STATIC) set(LIBTYPE STATIC)
if (SHARED) if (SHARED)
@ -44,7 +47,7 @@ if (STATICC)
endif () endif ()
# And link the libraries together # And link the libraries together
target_link_libraries(CreatureLib PUBLIC ${_LIBRARYLINKS}) target_link_libraries(CreatureLib PUBLIC ${_LIBRARYLINKS} Threads::Threads)
if (TESTS) if (TESTS)
# Create Test executable # Create Test executable

View File

@ -2,6 +2,7 @@
#define CREATURELIB_EVENTHOOK_HPP #define CREATURELIB_EVENTHOOK_HPP
#include <functional> #include <functional>
#include <thread>
#include <vector> #include <vector>
#include "../../Library/Exceptions/CreatureException.hpp" #include "../../Library/Exceptions/CreatureException.hpp"
#include "EventData.hpp" #include "EventData.hpp"
@ -18,6 +19,7 @@ namespace CreatureLib::Battling {
size_t _offset; size_t _offset;
size_t _capacity; size_t _capacity;
uint8_t* _memory = nullptr; uint8_t* _memory = nullptr;
std::thread* _currentThread = nullptr;
static constexpr size_t initialSize = 2048; static constexpr size_t initialSize = 2048;
static constexpr size_t stepSize = 1024; static constexpr size_t stepSize = 1024;
@ -33,7 +35,14 @@ namespace CreatureLib::Battling {
EventHook(const EventHook&) = delete; EventHook(const EventHook&) = delete;
EventHook& operator=(const EventHook&) = delete; EventHook& operator=(const EventHook&) = delete;
~EventHook() { free(_memory); } ~EventHook() {
free(_memory);
if (_currentThread != nullptr && _currentThread->joinable()) {
_currentThread->join();
delete _currentThread;
_currentThread = nullptr;
}
}
size_t GetPosition() const noexcept { return _offset; } size_t GetPosition() const noexcept { return _offset; }
size_t GetCapacity() const noexcept { return _capacity; } size_t GetCapacity() const noexcept { return _capacity; }
@ -41,6 +50,11 @@ namespace CreatureLib::Battling {
template <class T, class... parameters> void Trigger(parameters... args) { template <class T, class... parameters> void Trigger(parameters... args) {
if (_listeners.size() == 0) if (_listeners.size() == 0)
return; return;
if (_currentThread != nullptr && _currentThread->joinable()) {
_currentThread->join();
delete _currentThread;
_currentThread = nullptr;
}
if (_offset + sizeof(T) >= _capacity) { if (_offset + sizeof(T) >= _capacity) {
_capacity += stepSize; _capacity += stepSize;
auto newPtr = realloc(_memory, _capacity); auto newPtr = realloc(_memory, _capacity);
@ -52,12 +66,25 @@ namespace CreatureLib::Battling {
uint8_t* ptr = _memory + _offset; uint8_t* ptr = _memory + _offset;
T* event = new (ptr) T(args...); T* event = new (ptr) T(args...);
_offset += sizeof(T); _offset += sizeof(T);
_currentThread = new std::thread(&EventHook::RunListeners, this, event);
}
void RegisterListener(const EventHookFunc& func) { _listeners.push_back(func); }
void FinishListening() {
if (_currentThread != nullptr && _currentThread->joinable()) {
_currentThread->join();
delete _currentThread;
_currentThread = nullptr;
}
}
private:
void RunListeners(EventData* event) {
for (auto listener : _listeners) { for (auto listener : _listeners) {
try_creature(listener(event), "Exception in event listener"); try_creature(listener(event), "Exception in event listener");
} }
} }
void RegisterListener(const EventHookFunc& func) { _listeners.push_back(func); }
}; };
} }
#endif // CREATURELIB_EVENTHOOK_HPP #endif // CREATURELIB_EVENTHOOK_HPP

View File

@ -89,6 +89,7 @@ void Battle::CheckChoicesSetAndRun() {
this->_currentTurnQueue = nullptr; this->_currentTurnQueue = nullptr;
} }
TriggerEventListener<TurnEndEvent>(); TriggerEventListener<TurnEndEvent>();
_eventHook.FinishListening();
} }
ArbUt::BorrowedPtr<ChoiceQueue> Battle::GetCurrentTurnQueue() const noexcept { return _currentTurnQueue; } ArbUt::BorrowedPtr<ChoiceQueue> Battle::GetCurrentTurnQueue() const noexcept { return _currentTurnQueue; }

View File

@ -13,6 +13,7 @@ TEST_CASE("Build and use event hook", "[Battling]") {
for (size_t i = 0; i < 10; i++) { for (size_t i = 0; i < 10; i++) {
eventHook.Trigger<DamageEvent>(nullptr, DamageSource::AttackDamage, 0, 0); eventHook.Trigger<DamageEvent>(nullptr, DamageSource::AttackDamage, 0, 0);
} }
eventHook.FinishListening();
REQUIRE(events.size() == 10); REQUIRE(events.size() == 10);
REQUIRE(events[0]->GetKind() == EventDataKind::Damage); REQUIRE(events[0]->GetKind() == EventDataKind::Damage);
} }
@ -24,6 +25,7 @@ TEST_CASE("Build and use event hook a lot", "[Battling]") {
for (size_t i = 0; i < 10000; i++) { for (size_t i = 0; i < 10000; i++) {
eventHook.Trigger<DamageEvent>(nullptr, DamageSource::AttackDamage, 0, 0); eventHook.Trigger<DamageEvent>(nullptr, DamageSource::AttackDamage, 0, 0);
} }
eventHook.FinishListening();
REQUIRE(events.size() == 10000); REQUIRE(events.size() == 10000);
} }