성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
[정성태] Modules 창(Ctrl+Shift+U)을 띄워서, 해당 Op...
[정성태] 만드실 수 있습니다. 단지, Unity 엔진 내의 스크립트와 W...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>윈도우 운영체제의 시간 함수 (3) - QueryInterruptTimePrecise, QueryInterruptTime 함수</h1> <p> <a target='tab' href='http://www.sysnet.pe.kr/2/0/11063'>지난 글을 통해, GetTickCount와 timeGetTime의 동작 방식</a>을 살펴봤는데요. GetTickCount와 timeGetTime의 문제는 결국 운영체제가 메모리에 인터럽트가 발생할 때마다 그 횟수를 저장해 둔 변수의 값을 읽어온다는 것입니다. 그런데, 왜 그런 식으로 동작해야 할까요? 그냥 타이머 장치의 시간 값을 직접 구하는 Win32 API를 제공해주면 되는 것 아닐까요?<br /> <br /> 물론 이런 API가 있지만 아쉽게도 Windows 10부터 제공합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > QueryInterruptTimePrecise function ; <a target='tab' href='https://learn.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryinterrupttimeprecise'>https://learn.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryinterrupttimeprecise</a> </pre> <br /> <div style='BACKGROUND-COLOR: #ccffcc; padding: 10px 10px 5px 10px; MARGIN: 0px 10px 10px 10px; FONT-FAMILY: Malgun Gothic, Consolas, Verdana; COLOR: #005555'> lpInterruptTimePrecise [out]<br /> A pointer to a ULONGLONG in which to receive the interrupt-time count in system time units of 100 nanoseconds. Divide by ten million, or 1e7, to get seconds (there are 1e9 nanoseconds in a second, so there are 1e7 100-nanoseconds in a second).<br /> </div><br /> <br /> 100 나노초 단위라고 하니, 만약 이 함수의 반환 값이 1,000이라고 했을 때 밀리 초로 환산하려면 10,000으로 나누어 0.1ms를 계산할 수 있습니다.<br /> <br /> 주기적인 타이머 인터럽트에 영향을 안 받는지... 실제로 다음의 예제로 테스트할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > #include "stdafx.h" #include <Windows.h> // #include <realtimeapiset.h> #pragma comment(lib, "winmm.lib") typedef VOID (WINAPI *FuncQueryInterruptTimePrecise)(_Out_ PULONGLONG lpInterruptTimePrecise); int main() { int count = 0; HMODULE hModule = ::LoadLibrary(L"KernelBase.dll"); FuncQueryInterruptTimePrecise func_QueryInterruptTimePrecise = (FuncQueryInterruptTimePrecise)::GetProcAddress(hModule, "QueryInterruptTimePrecise"); if (func_QueryInterruptTimePrecise == nullptr) { printf("Not a Windows 10 PC\n"); return 0; } __int64 currentTime; __int64 gap[1000]; count = -1; int maxCount = 100; __int64 diff = 0; printf("QueryInterruptTimePrecise\n"); while (count ++ < maxCount) { <span style='color: blue; font-weight: bold'>func_QueryInterruptTimePrecise((PULONGLONG)&currentTime);</span> gap[count] = currentTime; printf("%I64d\n", currentTime); } currentTime = gap[0]; diff = 0; for (int i = 1; i < maxCount; i++) { diff = gap[i] - currentTime; printf("%I64d, %0.4f\n", diff, diff / 10000.0); currentTime = gap[i]; } return 0; } </pre> <br /> while 반복문에서 QueryInterruptTimePrecise 함수로 시간 값을 보관한 그 간격을 출력한 결과는 다음과 같습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 2294, 0.2294 2612, 0.2612 2514, 0.2514 2473, 0.2473 2463, 0.2463 2499, 0.2499 2461, 0.2461 2445, 0.2445 3450, 0.3450 2648, 0.2648 2508, 0.2508 2436, 0.2436 2421, 0.2421 2424, 0.2424 2421, 0.2421 2449, 0.2449 2418, 0.2418 2415, 0.2415 2397, 0.2397 ...[생략]... </pre> <br /> timeBeginPeriod + timeGetTime의 조합도 1ms 단위의 변화만 감지할 수 있었던 것에 비하면, 타이머 장치에 직접 접근하는 덕분에 정밀도는 훨씬 높아졌습니다.<br /> <br /> 그런데, 왜 이 좋은 것을 그동안 제공하지 않았던 것일까요? 제 생각이지만, 윈도우 PC 환경에서 1ms 미만의 정밀도를 요구하는 작업이 그다지 크게 중요하다고 생각지는 않았던 것이 아닌가 싶습니다. 그 외에 또 하나 이유라면, 사실 QueryInterruptTimePrecise는 타이머 디바이스로부터 직접 값을 읽어오기 때문에 호출 시간이 timeGetTime에 비해 더 느리다는 단점이 있습니다. 즉, 시간 정밀도를 높이려고 호출한 API 자체가 시간이 더 걸려 버리는 상황이 발생하는 것입니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 이와 유사한 함수의 이름으로 <a target='tab' href='https://learn.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryinterrupttime'>QueryInterruptTime</a>이 있는데 역시 Windows 10부터 제공됩니다. 이 함수는 timeGetTime과 동작 방식은 유사하나 대신 값이 64비트 변수에 담겨있고 100ns 단위의 시간 값을 제공합니다.<br /> <br /> 실제로 기본 타이머 설정인 15.625ms로 테스트를 해보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > #include "stdafx.h" #include <Windows.h> // #include <realtimeapiset.h> #pragma comment(lib, "winmm.lib") typedef VOID (WINAPI *FuncQueryInterruptTime)(_Out_ PULONGLONG lpInterruptTime); int main() { int count = 0; HMODULE hModule = ::LoadLibrary(L"KernelBase.dll"); FuncQueryInterruptTime func_QueryInterruptTime = (FuncQueryInterruptTime)::GetProcAddress(hModule, "QueryInterruptTime"); if (func_QueryInterruptTime == nullptr) { printf("Not a Windows 10 PC\n"); return 0; } __int64 currentTime; __int64 gap[1000]; count = -1; int maxCount = 100; __int64 diff = 0; printf("QueryInterruptTime\n"); while (count++ < mxunt) { <span style='color: blue; font-weight: bold'>func_QueryInterruptTime((PULONGLONG)&curentTime);</span> gap[count] = currentTime; printf("%I64d\n", currentTime); } currentTime = gap[0]; diff = 0; for (int i = 1; i < maxCount; i++) { diff = gap[i] - currentTime; printf("%I64d, %0.4f\n", diff, diff / 10000.0); currentTime = gap[i]; } return 0; } </pre> <br /> 출력된 시간 간격은 <a target='tab' href='http://www.sysnet.pe.kr/2/0/11063'>GetTickCount 때의 결과</a>와 유사하게 약 15.625ms 간격으로 변화가 발생합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0, 0.0000 ...[생략: 수십 번 반복]... 156319, 15.6319 ...[생략]... </pre> <br /> 물론, 위의 소스 코드에서 timeBeginPeriod(1) 코드를 한 번 호출해 주면 QueryInterruptTime은 1ms 단위로 변합니다.<br /> <br /> (<a target='tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?wid=11066&boardid=331301885'>첨부 파일은 이 글의 소스 코드를 포함</a>합니다.)<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1003
(왼쪽의 숫자를 입력해야 합니다.)