Coding Memo

Environment.TickCount 오버플로우 (대안) 본문

Language/C#

Environment.TickCount 오버플로우 (대안)

minttea25 2023. 11. 29. 22:09

C#에서 어떤 타이머를 구현하거나 실행 예약 등을 할 때 Environment.TickCount를 이용할 수 있다.

(물론 타이머는 기본적으로 제공하기는 한다. (System.Timers.Timer 등))

 

https://learn.microsoft.com/en-us/dotnet/api/system.environment.tickcount?view=net-8.0

 

Environment.TickCount Property (System)

Gets the number of milliseconds elapsed since the system started.

learn.microsoft.com

기계어로 번역되어 있는 부분이 많이 보이는데 항상 이해을 하지 못할 정도로 제대로 번역이 되어 있지 않은 경우가 많은 것 같다.

 

위 문서에도 나와 있지만, TickCount는 부호가 있는 32-bit 정수(32-bit signed integer)로 표현이 된다. 따라서 만약 int.Max( 2147483647)이후에는 int.Min( -2147483648)값이 되고야 만다.

 

실제 위 문서에서도 아래와 같이 사이클이 약 49.8일이라고 나와 있다.

 

 

위 TickCount를 계속해서 실행실행되고 있는 서버 등에서 사용한다면 큰일이 날 것이다.

 

그렇다면 이에 대한 대안이 무엇이 있을까?


1. Environment.TickCount64 사용

 

말그대로 Environment.TickCount와 같지만 32비트보다 훨씬 큰 수를 표현할 수 있는 long 타입(64-bit)의 tick을 가져올 수 있다. 참고로 int값이 최장 대략 49.8일이었지만, long 타입이라면 엄청나게 길다. (계산은 따로 안하겠다.)

 

long now = Environment.TickCount64;

 

그냥 단순히 이걸 사용하면 되겠네!

할 수도 있지만 아쉽게도 TickCount64는 일부 버전에서만 사용 가능하다. (물론 only Windows라면 사용해도 좋겠다.)

(딱 봐도, windows api인 GetTickCount64를 내부적으로 호출하여 가져오는 것처럼 보인다.)

 

ref: https://learn.microsoft.com/ko-kr/dotnet/api/system.environment.tickcount64?view=net-8.0

 

아쉽게도 .NET Standard에서는 지원하지 않는다.

 


2. Stopwatch 사용

 

Stopwatch 클래스는 말 그대로 스톱워치를 구현하는 클래스이다. 시작(Start)하여 시간을 측정(ElapsedMilliseconds)할 수 있고 정지(Stop) 시킬 수도 있고 리셋(Reset) 시킬 수도 있다. (ElapsedTick으로 tick을 가져올 수도 있다.)

 

주목해야 할 점은 시간 측정 단위가 Milliseconds 및 tick이고, 64-bit 정수라는 것이다.

 

Stopwatch 클래스는 System.Diagnostics 네임스페이스에 있다.

 

Stopwatch stopwatch = new Stopwatch();

stopwatch.Start(); // 시간 측정 시작

long now = stopwatch.ElapsedMilliseconds; // 경과 시간 가져오기
TimeSpan now_timespan = stopwatch.Elapsed; // 경과 시간 가져오기 (TimeSpan)
long elapsed_tick = stopwatch.ElapsedTicks; // 경과 tick 가져오기

stopwatch.Stop(); // 시간 측정 정지
stopwatch.Reset(); // 스톱워치 리셋

 

 

이 클래스는 대부분의 버전에서 사용 가능하다.

 

 

 

ref: https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.stopwatch?view=net-8.0

 

Note: 일반적으로 ElapsedMilliseconds는 경과한 시간을 밀리초 단위로 반환하는 과정에서 계산 시간이 걸릴 수 있어 약간의 정확도가 떨어 질 수도 있다. (ElapsedTicks가 좀 더 정확하지만, 시스템마다 차이가 있다.)


어떤 작업 예약을 처리하는 클래스를 만들어보면서 위 내용을 찾아보게 되었다. 타겟 프레임워크가 .NET Standard 2.1이라 Stopwatch를 사용하기로 했다.

 

아직 생각하고 있는 것은, Milliseconds로 할 것인지, Tick으로 할 것인지이다...