Skip to content

Commit

Permalink
Merge pull request #118 from IronsDu/opt
Browse files Browse the repository at this point in the history
add `addIntervalTimer` for schedule repeat timer;
  • Loading branch information
IronsDu authored Mar 12, 2022
2 parents aaabf03 + 1bbc21f commit 6a77f46
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 1 deletion.
54 changes: 53 additions & 1 deletion include/brynet/base/Timer.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <atomic>
#include <brynet/base/Noexcept.hpp>
#include <chrono>
#include <functional>
Expand Down Expand Up @@ -75,7 +76,26 @@ class Timer final
friend class TimerMgr;
};

class TimerMgr final
class RepeatTimer
{
public:
using Ptr = std::shared_ptr<RepeatTimer>;

void cancel()
{
mCancel.store(true);
}

bool isCancel() const
{
return mCancel.load();
}

private:
std::atomic_bool mCancel = {false};
};

class TimerMgr final : public std::enable_shared_from_this<TimerMgr>
{
public:
using Ptr = std::shared_ptr<TimerMgr>;
Expand All @@ -95,6 +115,22 @@ class TimerMgr final
return timer;
}

template<typename F, typename... TArgs>
RepeatTimer::Ptr addIntervalTimer(
std::chrono::nanoseconds interval,
F&& callback,
TArgs&&... args)
{
auto sharedThis = shared_from_this();
auto repeatTimer = std::make_shared<RepeatTimer>();
auto wrapperCallback = std::bind(std::forward<F>(callback), std::forward<TArgs>(args)...);
addTimer(interval, [sharedThis, interval, wrapperCallback, repeatTimer]() {
stubRepeatTimerCallback(sharedThis, interval, wrapperCallback, repeatTimer);
});

return repeatTimer;
}

void addTimer(const Timer::Ptr& timer)
{
mTimers.push(timer);
Expand Down Expand Up @@ -145,6 +181,22 @@ class TimerMgr final
}
}

private:
static void stubRepeatTimerCallback(TimerMgr::Ptr timerMgr,
std::chrono::nanoseconds interval,
std::function<void()> callback,
RepeatTimer::Ptr repeatTimer)
{
if (repeatTimer->isCancel())
{
return;
}
callback();
timerMgr->addTimer(interval, [timerMgr, interval, callback, repeatTimer]() {
stubRepeatTimerCallback(timerMgr, interval, callback, repeatTimer);
});
}

private:
class CompareTimer
{
Expand Down
6 changes: 6 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ enable_testing()
include_directories("${PROJECT_SOURCE_DIR}/include/")

add_executable(test_timer test_timer.cpp)
if(WIN32)
target_link_libraries(test_timer ws2_32)
elseif(UNIX)
find_package(Threads REQUIRED)
target_link_libraries(test_timer pthread)
endif()
add_test(TestTimer test_timer)

add_executable(test_wait_group test_wait_group.cpp)
Expand Down
32 changes: 32 additions & 0 deletions tests/test_timer.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#define CATCH_CONFIG_MAIN// This tells Catch to provide a main() - only do this in one cpp file
#include <brynet/base/Timer.hpp>
#include <brynet/base/WaitGroup.hpp>
#include <chrono>
#include <memory>
#include <thread>

#include "catch.hpp"

Expand Down Expand Up @@ -50,3 +52,33 @@ TEST_CASE("Timer are computed", "[timer]")

REQUIRE(upvalue == 2);
}

TEST_CASE("repeat timer are computed", "[repeat timer]")
{
auto timerMgr = std::make_shared<brynet::base::TimerMgr>();
auto wg = brynet::base::WaitGroup::Create();
wg->add(1);

std::atomic_int value = 0;
auto timer = timerMgr->addIntervalTimer(std::chrono::milliseconds(100), [&]() {
if (value.load() < 10)
{
value.fetch_add(1);
}
else
{
wg->done();
}
});

std::thread t([&]() {
wg->wait();
timer->cancel();
});
while (!timerMgr->isEmpty())
{
timerMgr->schedule();
}
t.join();
REQUIRE(value.load() == 10);
}

0 comments on commit 6a77f46

Please sign in to comment.