2009-07-07 8 views
45

각 웹 페이지가 생성되는 데 걸리는 시간을 계산하기 위해 모든 웹 페이지에서 호출되는 정적 타이머 클래스가 있습니다.정적 메서드는 스레드로부터 안전합니까?

제 질문은 정적 클래스 스레드가 안전합니까? 필자의 예에서 동시 사용자는 시작 및 중지 시간에 문제가 발생합니까? 예 : 내 시작 값과 끝 값을 덮어 쓰는 다른 스레드.

public static class Timer 
{ 
    private static DateTime _startTime; 
    private static DateTime _stopTime;  

    /// <summary> 
    /// Gets the amount of time taken in milliseconds 
    /// </summary> 
    /// <returns></returns> 
    public static decimal Duration() 
    { 
     TimeSpan duration = _stopTime - _startTime; 
     return duration.Milliseconds; 
    } 

    public static void Start() 
    { 
     _startTime = DateTime.Now; 
    } 

    public static void Stop() 
    { 
     _stopTime = DateTime.Now; 
    } 
} 

이 클래스는 정적이 아닌 클래스 여야합니까?

(이 클래스는 asp.net의 masterpage에서 호출됩니다.)

+7

MSDN : "클래스의 인스턴스에는 클래스의 모든 인스턴스 필드가 별도로 포함되어 있지만 각 정적 필드에는 하나의 복사본 만 있습니다." – colithium

답변

56

정적 메서드는 본질적으로 스레드로부터 안전하지 않습니다. 그것들은 인스턴스 메소드보다 CLR에 의해 다르게 처리됩니다. 차이점은 일반적으로 을 시도해야하며이 스레드로부터 안전하다는 것입니다. (나는 스레드로부터 안전하지 않은 .NET BCL 정적 메서드를 생각할 수 없다.) 일반적인 메서드는 개체를 만들고 한 스레드에서 반복적으로 사용하기 때문에 인스턴스 메서드는 종종 스레드로부터 안전하지 않습니다. 은 여러 스레드에서 사용해야하므로 관련 조정에는 개체를 안전하게 사용하는 것이 포함됩니다. 대다수의 경우, 객체 자체보다는 조정 코드에서 수행하는 것이 더 적절합니다. 일반적으로 작업의 전체 시퀀스를 효과적으로 원자 단위로 만들려고합니다. 객체 내에서 수행 할 수없는 작업입니다.

Timer 클래스는 스레드 안전성이 가장 확실합니다. 두 스레드가 서로의 데이터를 쉽게 밟을 수 있습니다 , 기간을 계산할 때 스레드가 "오래된"데이터를 사용하는 것을 막을 수있는 방법은 없습니다.

대신 Stopwatch 클래스를 사용하십시오. 그게 거기에있는 것입니다. 여러 스레드에서 하나의 인스턴스를 사용하려면 안전을 위해 정상적인 조치를 취해야하지만 일반적으로 훨씬 나은 위치에 있어야합니다. 틀림없이 Stopwatch도 완벽하지 않습니다. 자세한 내용은 this question 및 아래 주석을 참조하십시오. 그러나 적어도 유형이 설계된 것입니다. (누가 알겠습니까? 언젠가는 수정 될 수 있습니다 ...)

+4

Stopwatch 클래스에는 여러 코어 또는 다중 프로세서와 함께 사용하는 경우 자체적으로 문제가 있습니다. 스톱워치는 틱 수를 사용하여 지속 시간을 결정하며 BIOS의 버그로 인해 하나의 코어에서 스톱워치를 시작하고 다른 코어에서 스톱워치를 중지 할 수 있습니다.이 경우 두 코어의 틱 수는 동기화되지 않습니다. 나는 Vss2Git 오픈 소스 애플리케이션에서 스톱워치를 사용하고 때로는 음수 시간을주기 위해 시도한 것을 발견했다. Fpr more info http://stackoverflow.com/a/7919483/216440 –

+1

@SimonTewsi : 네, 전에 그것에 대해 들었습니다. 답변을 링크로 편집합니다. –

4

예, 당신 말이 맞아,이 클래스의 정적 멤버/접근은 그들을 서로 다른 사용자에 의해 덮어 쓰기하게됩니다.

이 때문에 인스턴스 및 비 정적 구성원이 있습니다.

18

타이머 클래스는 확실히 스레드로부터 안전하지 않습니다. 당신은 일반 클래스를 생성하고 당신이 시간을 측정 할 때마다 인스턴스화해야합니다

Timer timer = new Timer(); 

timer.Start(); 
//... 
timer.Stop(); 

decimal duration = timer.Duration(); 

더 나은 여전히이 내장 정확히 수행 .NET 클래스 :이

Stopwatch sw = Stopwatch.StartNew(); 

sw.Stop(); 

TimeSpan duration = sw.Elapsed; 
20

좋은 토론 here은 메커니즘이 왜 당신의 예제가 스레드로부터 안전하지 않은지에 초점을 맞추고 있습니다.

요약하면, 먼저 정적 변수가 공유됩니다. 로컬 변수를 정적 메서드에 대해 로컬 인 경우에도 로컬 변수로 만들 수 있지만 여전히 자체 스택 프레임을 가져 와서 스레드로부터 안전합니다. 또한 정적 변수 (즉, 잠금 및/또는이 스레드에서 다른 사람이 언급 한 다른 멀티 스레드 프로그래밍 기법)를 보호하면 샘플 정적 클래스가 스레드로부터 안전해질 수 있습니다.

둘째, 예제가 수정 한 외부 변수 인스턴스를 갖지 않거나 상태가 다른 스레드에 의해 영향을받을 수 있으므로이 예제는 스레드로부터 안전합니다.

+0

우수한 정보입니다. 정확히 여기 내가 찾은 것입니다. 정적 메서드가 로컬 변수 만 사용하는 경우 스레드로부터 안전합니까? 건배. –

+4

예. 그러나 정적 클래스 변수가 아니라 메소드에 대한 변수 일 필요가 있다는 것을 기억하십시오. (때로는 클래스 변수를 지역 변수라고 부르지 만 그럴 수도 있습니다.) "지역 변수 만 사용합니다"라고 말했기 때문에 전달 된 변수에 대한 참조를 지정하지 않았다는 것을 의미합니다. 매개 변수를 로컬 변수에 추가하십시오. – Bill

관련 문제