공부/게임서버
Thread.Sleep 과 Thread.Yield
samosa
2024. 11. 12. 17:31
while (true)
{
if (Interlocked.CompareExchange(ref _locked, 1, 0) == 0)
return;
// Option 1
Thread.Sleep(1);
// Option 2
Thread.Sleep(0);
// Option 3
Thread.Yield();
}
이 코드에서 Thread.Sleep(1)
, Thread.Sleep(0)
, 그리고 Thread.Yield()
는 모두 CPU와 메모리 자원의 사용과 관련이 있다. 메모리 측면에서 각각의 동작을 더 깊이 설명하면 다음과 같다.
1. Thread.Sleep(1)
- 동작:
Thread.Sleep(1)
은 현재 스레드를 최소 1밀리초 동안 대기 상태로 전환한다. 이때 운영 체제의 스케줄러는 다른 스레드에게 CPU 실행 권한을 넘겨준다. - 메모리 측면:
- 스레드가
Sleep(1)
상태에 들어가면, 스레드의 실행 상태가 대기 상태로 변경되며 CPU에서 실행이 멈춘다. 이때 스레드는 현재 레지스터 값과 스택 포인터 등 컨텍스트 정보를 저장하고 메모리의 대기열에 포함된다. - CPU 캐시와 관련해, 스레드가 다시 활성화될 때 캐시가 다른 작업으로 인해 무효화될 수 있다. 이로 인해 스레드가 재개될 때 메모리의 캐시 미스(cache miss)가 발생할 가능성이 있다.
- 이는 메모리 접근 시간과 CPU 효율성을 저하시킬 수 있다.
- 스레드가
2. Thread.Sleep(0)
- 동작:
Thread.Sleep(0)
은 현재 스레드의 실행을 즉시 양보하지만, 동일한 우선순위의 다른 스레드에게만 실행 기회를 제공한다. 만약 실행 대기 중인 같은 우선순위의 스레드가 없다면, 현재 스레드가 다시 실행된다. - 메모리 측면:
- 스레드의 컨텍스트는 전환되지 않으므로 메모리 상태가 크게 변경되지 않는다. 그러나, CPU가 실행을 양보할 때 캐시 라인에 다른 스레드의 데이터가 로드될 수 있다.
- 캐시 데이터가 그대로 유지되기 때문에, 다시 실행될 때 캐시 미스가 덜 발생할 수 있다. 이로 인해 메모리 액세스 시간과 CPU 효율성이 비교적 높다.
3. Thread.Yield()
- 동작:
Thread.Yield()
는 스레드가 실행 중인 프로세서의 실행을 다른 논리적 프로세서나 다른 스레드에게 양보한다. 특히, 대기 중인 스레드가 있다면 실행을 넘기며, 없을 경우 현재 스레드가 계속 실행된다. - 메모리 측면:
Yield()
는 컨텍스트 스위칭이 발생할 수 있으며, 이 과정에서 CPU의 캐시 상태가 바뀔 수 있다. 캐시 히트(cache hit) 비율은 여전히 유지될 수 있지만, 스레드가 완전히 대기 상태로 전환되는Sleep(1)
보다는 캐시 무효화의 가능성이 적다.- 메모리 일관성 측면에서 스레드가 다른 스레드에게 실행을 넘기면서 메모리 버퍼의 플러시(갱신)나 메모리 가시성 문제가 발생할 수 있다. 하지만 일반적으로 운영 체제의 메모리 관리 메커니즘에 의해 이러한 문제는 제어된다.
요약
Thread.Sleep(1)
은 스레드를 대기 상태로 만들어 캐시가 무효화될 가능성이 높으며, 메모리 접근 성능이 떨어질 수 있다.Thread.Sleep(0)
은 컨텍스트 스위칭 없이 실행 우선순위를 조정하므로 메모리 캐시 상태가 유지되며, 메모리 액세스 성능이 비교적 높게 유지된다.Thread.Yield()
는 다른 스레드에게 CPU 실행을 넘기면서 캐시 무효화 가능성이 있지만, 캐시 히트율이Sleep(1)
보다는 높다.
이 기법들은 메모리와 CPU 사용률을 조절하기 위한 도구로, 시스템 성능 요구 사항에 따라 적절한 방법을 선택하여 사용한다.