C++ - Win32API 스레드 풀을 사용하는 타이머
- Windows Vista부터 사용 가능.
- CreateThreadpoolTimer, SetThreadpoolTimer API 사용.
- ‘윈도우 시스템 프로그램을 구현하는 기술(한빛미디어)’에 설명이 잘 나와 있음
예제 코드 출처: https://github.com/billlin0904/librapid
using TimerPtr = std::shared_ptr<Timer>;
class Timer {
public:
using TimeoutCallback = std::function<void(void)>;
static TimerPtr createTimer();
void start(TimeoutCallback callback, uint32_t interval, bool immediately = true, bool once = false);
void stop();
private:
void timeout();
static void CALLBACK onTimeoutCallback(PTP_CALLBACK_INSTANCE instance, PVOID param, PTP_TIMER timer);
TimeoutCallback onTimeoutCallback_;
TP_CALLBACK_ENVIRON callbackEnviron_;
PTP_TIMER handle_;
};
inline TimerPtr Timer::createTimer() {
return std::make_shared<Timer>();
}
Timer::Timer()
: handle_(nullptr) {
::InitializeThreadpoolEnvironment(&callbackEnviron_);
handle_ = ::CreateThreadpoolTimer(onTimeoutCallback, this, &callbackEnviron_);
if (!handle_) {
//throw Exception(::GetLastError());
}
}
Timer::~Timer() {
stop();
}
void Timer::start(TimeoutCallback callback, uint32_t interval, bool immediately, bool once) {
onTimeoutCallback_ = callback;
FILETIME dueTime;
*reinterpret_cast<PLONGLONG>(&dueTime) = -static_cast<LONGLONG>(MILLI_SECOND_TO_NANO100(0));
::SetThreadpoolTimer(handle_, &dueTime, once ? 0 : interval, 0);
}
void Timer::stop() {
if (handle_ != nullptr) {
::SetThreadpoolTimer(handle_, nullptr, 0, 0);
::WaitForThreadpoolTimerCallbacks(handle_, TRUE);
::CloseThreadpoolTimer(handle_);
::DestroyThreadpoolEnvironment(&callbackEnviron_);
handle_ = nullptr;
}
}
void Timer::timeout() {
try {
onTimeoutCallback_();
} catch (...) { }
}
사용 예
{
timer_.start(std::bind(&TimingWheel::onTick, this), tickDuration_);
}
class TimingWheel
{
uint32_t tickDuration_;
}
void TimingWheel::onTick() {
std::lock_guard<platform::Spinlock> guard{ lock_ };
auto & bucket = buckets_[nextIndex_];
for (auto &callback : bucket) {
if (callback.second != nullptr) {
callback.second();
if (callback.first) {
callback.second = nullptr;
}
}
}
nextIndex_ = (nextIndex_ + 1) % buckets_.size();
}
이 글은 2020-02-26에 작성되었습니다.