2009-07-07 22 views
45

Ich habe eine statische Timer-Klasse, die von jeder Webseite aufgerufen wird, um zu berechnen, wie lange jede Seite aufgebaut werden muss.Sind statische Methoden Thread sicher

Meine Frage ist sind statische Klassen Thread Safe? In meinem Beispiel verursachen gleichzeitige Benutzer ein Problem mit meinen Start- und Stoppzeiten? Beispielsweise überschreiben andere Threads meine Start- und Stoppwerte.

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; 
    } 
} 

Sollte diese Klasse eine nicht statische Klasse sein?

(Diese Klasse von der asp.net Masterpage genannt wird.)

+7

MSDN: „Während eine Instanz einer Klasse eine separate Kopie aller Instanzfelder der Klasse enthält, gibt es nur eine Kopie jedes statische Feld.“ – colithium

Antwort

56

Statische Methoden sind nicht inhärent thread-safe. Sie werden von der CLR nicht anders behandelt als Instanzmethoden. Der Unterschied ist, dass man generell versuchen sollte sie threadsicher zu machen. (Ich kann mir keine statischen statischen .NET BCL-Methoden vorstellen, die nicht threadsicher sind.) Instanzmethoden sind oft nicht threadsicher, da das typische Muster darin besteht, ein Objekt zu erstellen und es wiederholt in einem Thread zu verwenden müssen aus mehreren Threads verwendet werden, die Koordination beinhaltet, sicherzustellen, dass das Objekt sicher verwendet wird. In sehr vielen Fällen ist dies im Koordinationscode geeigneter als im Objekt selbst. (Normalerweise möchten Sie ganze Folgen von Operationen effektiv atomar machen - etwas, was nicht innerhalb des Objekts gemacht werden kann.)

Ihre Timer Klasse ist definitiv nicht threadsicher: zwei Threads können sich gegenseitig leicht gegenseitig Daten aufstampfen und es gibt nichts, was einen Thread daran hindern könnte, "veraltete" Daten zu verwenden, wenn man die Dauer berechnet.

Verwenden Sie stattdessen die Klasse Stopwatch - dafür ist es da. Zugegeben, wenn Sie eine Instanz aus mehreren Threads verwenden möchten, müssen Sie die normalen Schritte ausführen, um Sicherheit zu gewährleisten, aber Sie werden im Allgemeinen in einer viel besseren Position sein. Zugegeben, Stopwatch ist bei weitem nicht perfekt - siehe this question und den Kommentar unten für weitere Details - aber es ist zumindest was der Typ ist für. (Wer weiß, kann es irgendwann behoben werden ...)

+4

Die Stoppuhr-Klasse hat eigene Probleme, wenn Sie sie mit mehreren Kernen oder mehreren Prozessoren verwenden. Stoppuhr verwendet eine Tick-Zählung, um die Zeitdauer zu bestimmen, und aufgrund eines Fehlers im BIOS kann die Stoppuhr auf einem Kern gestartet und auf einem anderen angehalten werden, wobei die Tick-Zählungen auf den beiden Kernen nicht synchron sind. Ich entdeckte dies in der Open-Source-Anwendung Vss2Git, die eine Stoppuhr verwendete und manchmal versuchte, eine negative Zeitdauer anzugeben. Fpr mehr Info siehe http://Stackoverflow.com/a/7919483/216440 –

+1

@SimonTewsi: Ja, ich habe darüber schon einmal gehört. Wird einen Link in die Antwort bearbeiten. –

4

Ja, du hast Recht, die statischen Mitglieder/Accessoren auf dieser Klasse wollen sie von verschiedenen Benutzern überschrieben werden.

Aus diesem Grund haben Sie Instanzen und nicht statische Mitglieder.

18

Ihre Timer-Klasse ist definitiv nicht Thread-sicher. Sie sollten eine normale Klasse erstellen und instanziiert es jedes Mal, wenn Sie die Zeit messen müssen:

Timer timer = new Timer(); 

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

decimal duration = timer.Duration(); 

Noch besser ist, gibt es eine eingebaute in .NET-Klasse, die genau das tut:

Stopwatch sw = Stopwatch.StartNew(); 

sw.Stop(); 

TimeSpan duration = sw.Elapsed; 
20

Es ist eine gute Diskussion here, die mehr auf die Mechanismen und Gründe dafür konzentriert, warum Ihr Beispiel nicht Thread-sicher ist.

Zusammenfassend werden zunächst Ihre statischen Variablen geteilt. Wenn Sie sie zu lokalen Variablen machen könnten, obwohl sie für eine statische Methode lokal sind, würden sie dennoch ihren eigenen Stack-Frame erhalten und somit Thread-sicher sein. Wenn Sie Ihre statischen Variablen anderweitig schützen (dh Sperren und/oder andere Multi-Thread-Programmiertechniken, die von anderen in diesem Thread erwähnt werden), können Sie Ihre statische Beispielklasse auch threadsicher machen.

Zweitens, weil Ihr Beispiel in externen Variablen Instanzen dauert nicht, die Sie oder dessen Zustand ändern könnte von einem anderen Thread auf sich einwirken lassen, ist Ihr Beispiel auch in dieser Hinsicht Thread-sicher.

+0

Ausgezeichnete Informationen, das ist genau was ich hierher gekommen bin zu finden: Wenn eine statische Methode nur lokale Variablen verwendet, ist es Thread-sicher? Prost. –

+4

Ja. Aber denken Sie daran, es muss eine lokale Variable für die Methode sein - keine statische Klassenvariable. (Ich denke manchmal, Klassenvariablen werden als lokal bezeichnet, aber ich kann darüber verwechselt werden.) Da Sie sagten, „nur eine lokale Variable verwendet“, ich nehme auch, dass implizieren, dass Sie nicht eine Referenz eines zuweisen gebenen in Parameter zu einer lokalen Variablen. – Bill

Verwandte Themen