MSDN에 따르면 Stopwatch
클래스 인스턴스 메서드는 다중 스레드 액세스에 안전하지 않습니다. 이것은 또한 개별 방법을 검사하여 확인할 수 있습니다. _stopwatch.ElapsedMilliseconds
이후간단한 잠금없는 스톱워치
public class ElapsedTimer : IElapsedTimer
{
/// Shared (static) stopwatch instance.
static readonly Stopwatch _stopwatch = Stopwatch.StartNew();
/// Stopwatch offset captured at last call to Reset
long _lastResetTime;
/// Each instance is immediately reset when created
public ElapsedTimer()
{
Reset();
}
/// Resets this instance.
public void Reset()
{
Interlocked.Exchange(ref _lastResetTime, _stopwatch.ElapsedMilliseconds);
}
/// Seconds elapsed since last reset.
public double SecondsElapsed
{
get
{
var resetTime = Interlocked.Read(ref _lastResetTime);
return (_stopwatch.ElapsedMilliseconds - resetTime)/1000.0;
}
}
}
는 기본적으로이다 : 만 필요하기 때문에
그러나, 간단한 여전히 같은 것을 사용하여 잠금없는 일을 할 수 있다면 내 코드의 여러 장소에서 타이머, 궁금 "시간 경과" QueryPerformanceCounter
을 호출하면 여러 스레드에서 호출하는 것이 안전하다고 생각합니까? 일반 Stopwatch
과의 차이점은이 클래스는 기본적으로 항상 실행 중이므로 Stopwatch
처럼 추가 상태 ("실행 중"또는 "중지됨")를 유지할 필요가 없다는 것입니다.
(업데이트) 아래 질문에 대해 답 @Scott에 의해 제안 후, 나는 Stopwatch
원시 QueryPerformanceCounter
틱을 반환하는 간단한 정적 GetTimestamp
방법을 제공하는 것을 깨달았다. 이다,
public class ElapsedTimer : IElapsedTimer
{
static double Frequency = (double)Stopwatch.Frequency;
/// Stopwatch offset for last reset
long _lastResetTime;
public ElapsedTimer()
{
Reset();
}
/// Resets this instance.
public void Reset()
{
// must keep in mind that GetTimestamp ticks are NOT DateTime ticks
// (i.e. they must be divided by Stopwatch.Frequency to get seconds,
// and Stopwatch.Frequency is hw dependent)
Interlocked.Exchange(ref _lastResetTime, Stopwatch.GetTimestamp());
}
/// Seconds elapsed since last reset
public double SecondsElapsed
{
get
{
var resetTime = Interlocked.Read(ref _lastResetTime);
return (Stopwatch.GetTimestamp() - resetTime)/Frequency;
}
}
}
이 코드의 아이디어, 명확히하기 :
- 검사의 간단하고 빠른 방법을 가지고 즉, 코드는 스레드 안전 인이에 수정 될 수 있습니다 시간이 소정의 운전/이벤트 경과 한 경우
- 방법한다 다중 스레드로부터 호출이 아닌 경우 손상된 상태
- OS 클럭 변경 (사용자 변경, NTP 동기화, 시간대 등) 둔감 있어야
나는 비슷한이로 사용합니다 :
private readonly ElapsedTimer _lastCommandReceiveTime = new ElapsedTimer();
// can be invoked by multiple threads (usually threadpool)
void Port_CommandReceived(Cmd command)
{
_lastCommandReceiveTime.Reset();
}
// also can be run from multiple threads
void DoStuff()
{
if (_lastCommandReceiveTime.SecondsElapsed > 10)
{
// must do something
}
}
Interlocked.Exchange와 Interlocked.Read는 내가 믿는 잠금 메커니즘입니다. –
@ justin.m.chase : 아니오, 둘 다 잠금이 없습니다 (원자 성을 보장하면서). x64 플랫폼에서는 실제 CPU 명령어로 JITted를 얻습니다. – Lou
지금까지 QueryPerformanceCounter를 직접 호출하지 않는 이유는 무엇입니까? –