Skip to content

Instantly share code, notes, and snippets.

@takamin
Last active August 29, 2015 14:06
Show Gist options
  • Save takamin/3a0a40beddf6447c4848 to your computer and use it in GitHub Desktop.
Save takamin/3a0a40beddf6447c4848 to your computer and use it in GitHub Desktop.
TimerThread
#pragma once
#include <windows.h>
#ifdef _DEBUG
#include <deque>
#endif
class TimerThread {
public:
TimerThread();
virtual ~TimerThread();
void setInterval(int interval);
void start();
void stop();
protected:
virtual void run() = 0;
protected:
HANDLE stop_event;
HANDLE thead_handle;
int interval;
private:
static DWORD WINAPI ThreadMain(LPVOID data);
#ifdef _DEBUG
private:
std::deque<long> clock_log;
#endif
};
#include "stdafx.h"
#include <iostream>
#include <time.h>
#include <cassert>
#include "TimerThread.h"
TimerThread::TimerThread()
: thead_handle(INVALID_HANDLE_VALUE),
stop_event(INVALID_HANDLE_VALUE), interval(0)
{
}
TimerThread::~TimerThread()
{
#ifdef _DEBUG
std::deque<long>::iterator t = clock_log.begin();
double dur_avg = 0.0;
clock_t prevT = -1;
std::cerr
<< "---- " << std::endl
<< "■直近" << clock_log.size()
<< "回の実行間隔 : " << std::endl;
for (; t != clock_log.end(); t++) {
clock_t T = *t;
if (prevT >= 0) {
std::cerr << "+" << (T - prevT) << "/";
dur_avg += (T - prevT);
}
prevT = T;
}
std::cerr << std::endl;
if (clock_log.size() > 1) {
dur_avg /= (clock_log.size() - 1);
std::cerr
<< "■平均: " << dur_avg << "[ms] "
<< "■" << (1000.0 / dur_avg) << "回/秒"
<< std::endl;
}
#endif
}
void TimerThread::setInterval(int interval)
{
assert(interval > 0);
this->interval = interval;
}
void TimerThread::start()
{
assert(stop_event == INVALID_HANDLE_VALUE);
assert(thead_handle == INVALID_HANDLE_VALUE);
//終了要求イベント
stop_event = ::CreateEvent(NULL, FALSE, FALSE, NULL);
assert(stop_event != NULL);
this->interval = interval;
thead_handle = ::CreateThread(0, 0,
TimerThread::ThreadMain, (LPVOID)this,
0, NULL);
assert(thead_handle != NULL);
}
void TimerThread::stop()
{
assert(stop_event != NULL);
assert(thead_handle != NULL);
::SetEvent(stop_event);
WaitForSingleObject(thead_handle, INFINITE);
::CloseHandle(thead_handle);
thead_handle = INVALID_HANDLE_VALUE;
::CloseHandle(stop_event);
stop_event = INVALID_HANDLE_VALUE;
}
DWORD WINAPI TimerThread::ThreadMain(LPVOID data)
{
TimerThread* thread = (TimerThread*)data;
clock_t sleep_t = 0; //累積待ち時間
long run_counter = 0x7fffffff; //実行カウンター
clock_t t0 = 0; //初回実行時刻
while (::WaitForSingleObject(thread->stop_event, 0) != WAIT_OBJECT_0) {
//カウンターリセット
if (run_counter > 0x7ffffff0) {
run_counter = 0;
t0 = clock();
}
//タイマー処理実行
thread->run();
run_counter++;
//時間待ち
sleep_t += ((t0 + run_counter * thread->interval) - clock());
if (sleep_t > 0) {
Sleep(sleep_t);
sleep_t = 0;
}
else {
Sleep(1);
sleep_t -= 1;
}
#ifdef _DEBUG
//実行間隔計測
clock_t t = clock();
thread->clock_log.push_back(t);
if (thread->clock_log.size() > 10000) {
thread->clock_log.pop_front();
}
#endif
}
::ExitThread(0);
return 0;
}
#include "stdafx.h"
#include "TimerThread.h"
#include <iostream>
class SampleTimerThread : public TimerThread {
public:
SampleTimerThread() : counter(0) {}
protected:
void run() {
std::cerr << counter << std::endl;
counter++;
}
private:
int counter;
};
int _tmain(int argc, _TCHAR* argv[])
{
SampleTimerThread thread1;
SampleTimerThread thread2;
SampleTimerThread thread3;
thread1.setInterval(30);
thread2.setInterval(100);
thread3.setInterval(1000);
thread1.start();
thread2.start();
thread3.start();
Sleep(30000);
thread1.stop();
thread2.stop();
thread3.stop();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment