From 208bb097dd4490e0852ff5b34bbd5ce714b5c44d Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Fri, 7 Aug 2020 12:20:59 +0200 Subject: [PATCH] Make event listeners threaded. Signed-off-by: Deukhoofd --- CMakeLists.txt | 5 +++- src/Battling/EventHooks/EventHook.hpp | 33 ++++++++++++++++++++++++--- src/Battling/Models/Battle.cpp | 1 + tests/BattleTests/EventHookTests.cpp | 2 ++ 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c794db..e70db46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,9 @@ option(STATICC "Whether gcc and stdc++ should be linked statically to the librar include(CmakeConanSetup.cmake) SetupConan() +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) + # Set whether we want a static or shared library. set(LIBTYPE STATIC) if (SHARED) @@ -44,7 +47,7 @@ if (STATICC) endif () # And link the libraries together -target_link_libraries(CreatureLib PUBLIC ${_LIBRARYLINKS}) +target_link_libraries(CreatureLib PUBLIC ${_LIBRARYLINKS} Threads::Threads) if (TESTS) # Create Test executable diff --git a/src/Battling/EventHooks/EventHook.hpp b/src/Battling/EventHooks/EventHook.hpp index 10be88b..59628a2 100644 --- a/src/Battling/EventHooks/EventHook.hpp +++ b/src/Battling/EventHooks/EventHook.hpp @@ -2,6 +2,7 @@ #define CREATURELIB_EVENTHOOK_HPP #include +#include #include #include "../../Library/Exceptions/CreatureException.hpp" #include "EventData.hpp" @@ -18,6 +19,7 @@ namespace CreatureLib::Battling { size_t _offset; size_t _capacity; uint8_t* _memory = nullptr; + std::thread* _currentThread = nullptr; static constexpr size_t initialSize = 2048; static constexpr size_t stepSize = 1024; @@ -33,7 +35,14 @@ namespace CreatureLib::Battling { EventHook(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 GetCapacity() const noexcept { return _capacity; } @@ -41,6 +50,11 @@ namespace CreatureLib::Battling { template void Trigger(parameters... args) { if (_listeners.size() == 0) return; + if (_currentThread != nullptr && _currentThread->joinable()) { + _currentThread->join(); + delete _currentThread; + _currentThread = nullptr; + } if (_offset + sizeof(T) >= _capacity) { _capacity += stepSize; auto newPtr = realloc(_memory, _capacity); @@ -52,12 +66,25 @@ namespace CreatureLib::Battling { uint8_t* ptr = _memory + _offset; T* event = new (ptr) T(args...); _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) { try_creature(listener(event), "Exception in event listener"); } } - - void RegisterListener(const EventHookFunc& func) { _listeners.push_back(func); } }; } #endif // CREATURELIB_EVENTHOOK_HPP diff --git a/src/Battling/Models/Battle.cpp b/src/Battling/Models/Battle.cpp index dfa8c9b..3e310f7 100644 --- a/src/Battling/Models/Battle.cpp +++ b/src/Battling/Models/Battle.cpp @@ -89,6 +89,7 @@ void Battle::CheckChoicesSetAndRun() { this->_currentTurnQueue = nullptr; } TriggerEventListener(); + _eventHook.FinishListening(); } ArbUt::BorrowedPtr Battle::GetCurrentTurnQueue() const noexcept { return _currentTurnQueue; } diff --git a/tests/BattleTests/EventHookTests.cpp b/tests/BattleTests/EventHookTests.cpp index 1568cfe..668f091 100644 --- a/tests/BattleTests/EventHookTests.cpp +++ b/tests/BattleTests/EventHookTests.cpp @@ -13,6 +13,7 @@ TEST_CASE("Build and use event hook", "[Battling]") { for (size_t i = 0; i < 10; i++) { eventHook.Trigger(nullptr, DamageSource::AttackDamage, 0, 0); } + eventHook.FinishListening(); REQUIRE(events.size() == 10); 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++) { eventHook.Trigger(nullptr, DamageSource::AttackDamage, 0, 0); } + eventHook.FinishListening(); REQUIRE(events.size() == 10000); }