#ifndef __TNSTimer_H #define __TNSTimer_H /* NanoSeconds Timer 나노세컨 타이머(쓰레드 베이스) 컴퓨터 성능에 따라 나노초(1/1000000000초) 수준까지 타이머 실행 가능. WIn32의 타이머나, VCL의 TTimer에 비해 정확도가 높으며 기존 타이머가 최소 10~40ms 정도의 인터벌을 가질수 있는 것에 비해 이 나노세컨 타이머는 나노급 시간까지도 가능하다. 물론 컴퓨터 성능이 받쳐준다면. 기본 동작은 1 MilliSeconds로 동작한다. 주지: 쓰레드 베이스로 동작하며, 쓰레드 내에서 루프를 돌며 CPU의 동작 속도를 계산해 타이머를 동작시키는데, MilliSeconds 이하 타이머에서는 CPU 부하를 많이 쓰는 단점이 있다. 이는 쓰레드가 Sleep 없이 루프를 돌기 때문인데, MilliSeconds 이하 타이머 동작에서는 Sleep을 쓸수가 없다. Sleep의 기본적인 동작은 CPU가 본 쓰레드에 활당된 Instruction 동작을 멈추고 다른 프로세스에 CPU를 양보하는 것인데, 이를 ContextSwitching 이라고 하고 이 동작이 MilliSeconds 급으로 이루어지기 때문이다. 즉 한번 ContextSwitching 이 일어나서 CPU의 제어권을 다른 프로세스로 넘겼다가 이 쓰레드가 다시 받기까지는 최소 MilliSeconds의 시간을 소비하기 때문에 Sleep을 써서는 MilliSeconds 이하 타이머를 만들수 없다. 그래서 MilliSeconds 이하급 타이머에서는 항상 bUseSleep = false 상태에서 동작해야 하며, CPU 부하를 많이 쓰기 때문에, 이를 고려해 적정한 시간 동안 쓰도록 해야 한다. CPU 부하를 많이 쓴다고 했는데, OS는 하나의 프로세스에 과도한 CPU 부하가 걸리지 않게 적절하게 ContextSwitching을 하기 때문에, 지나치게 높은 수준으로 다른 쓰레드의 동작에 큰 영향을 줄 정도로는 절대 높아지지 않는다. Millisecond = 1/1000초 Microsecond = 1/1000000초 Nanoseconds = 1/1000000000초 1 Millisecond = 1000 Microseconds 1 Millisecond = 1000000 Nanoseconds Written by 김태성. */ class TNSTimer : public TThread { private: int NanoSeconds; bool FEnabled; LARGE_INTEGER NSTime, NSFreq; private: double __fastcall GetMilliSeconds() { return NanoSeconds / 1000000.0; } void __fastcall SetMilliSeconds(double ms) { NanoSeconds = ms * 1000000.0; } public: typedef void (__closure *TNSTimerMethod)(); TNSTimerMethod NSTimerMethod; bool bUseSleep; public: __fastcall TNSTimer() : TThread(false) { NSTimerMethod = NULL; FEnabled = false; NanoSeconds = 1000000; // default는 1 MilliSeconds NSTime.QuadPart = 0; NSFreq.QuadPart = 0; bUseSleep = false; FreeOnTerminate = true; SetStdTime(); } void __fastcall Execute() { while(!Terminated) { if (NanoSeconds == 0 || !FEnabled) { Sleep(1); continue; } LARGE_INTEGER cur_ns; QueryPerformanceCounter(&cur_ns); LONGLONG between = cur_ns.QuadPart - NSTime.QuadPart; double second = (double)between / NSFreq.QuadPart; // 이렇게 하면 초로 나온다. if (second * 1000000 * 1000 < NanoSeconds) { if (bUseSleep) Sleep(0); continue; } NSTime = cur_ns; if (NSTimerMethod) NSTimerMethod(); } } void SetStdTime() { QueryPerformanceCounter(&NSTime); QueryPerformanceFrequency(&NSFreq); } // 나노세컨으로 인터벌 지정, 1은 백만분의 1밀리세컨. 100000은 0.1 밀리세컨. __property int NanoSecondsInterval = { read=NanoSeconds, write=NanoSeconds }; // -밀리세컨으로 인터벌 지정: 0.1 MiliSeconds, 0.01 MiliSeconds 식으로 지정 가능. __property double MilliSecondsInterval = { read=GetMilliSeconds, write=SetMilliSeconds }; // 타이머 동작 on/off 제어 __property bool Enabled = { read=FEnabled, write=FEnabled }; }; #endif