2009-07-07 7 views
45

私は各ページが構築された時間を計算するためにANY Webページから呼び出される静的タイマークラスを持っています。静的メソッドはスレッドセーフですか

私の質問は静的クラスのスレッドセーフですか?私の例では、同時ユーザーは私の開始時間と停止時間に問題を引き起こしますか?例:私の開始値と終了値を上書きする異なるスレッド。

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のマスターページから呼び出されます。)

+7

MSDN: "クラスのインスタンスには、クラスのすべてのインスタンスフィールドの個別のコピーが含まれていますが、各静的フィールドのコピーは1つだけです。 – colithium

答えて

56

スタティックメソッドは、本質的にスレッドセーフではありません。それらは、インスタンスメソッドよりもCLRで扱われます。違いは、一般的ににしようとするとスレッドセーフであることです。 (私は、スレッドセーフではない.NET BCL静的メソッドは考えられません)。インスタンスメソッドは、通常、オブジェクトを作成して1つのスレッドから繰り返し使用するパターンなので、スレッドセーフではないことがよくあります。 は複数のスレッドから使​​用する必要がありますが、調整にはオブジェクトを安全に使用することが含まれます。非常に多くの場合、オブジェクト自体よりもコーディネートコードで行う方が適切です。 (通常は、操作全体を効果的に原子的にする - オブジェクト内で実行できないもの)

Timerクラスは、スレッドセーフではありません。2つのスレッドは、お互いのデータを簡単に期間を計算するときにスレッドが「古い」データを使用するのを止めるものは何もありません。

代わりにStopwatchクラスを使用してください。これはそのためのものです。確かに、複数のスレッドから1つのインスタンスを使用する場合は、安全を確保するための通常の手順を実行する必要がありますが、一般的にははるかに優れた立場にあります。確かにStopwatchも完璧ではありません。詳しくは、this questionと下記のコメントを参照してください。しかし、少なくともそのタイプが設計されているものです。 (だれが知っている、それはいくつかの時間を固定することがあります...)

+4

Stopwatchクラスには、複数のコアまたは複数のプロセッサで使用している場合、独自の問題があります。ストップウォッチはティックカウントを使用して継続時間を決定し、BIOSのバグのために1つのコアでストップウォッチを開始し、別のコアでストップウォッチを停止することができます。私はVss2Gitオープンソースアプリケーションでこれを発見しました。このアプリケーションでは、ストップウォッチを使用し、時には負の時間を与えようと試みました。 Fpr詳細情報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です。

要約すると、まず、静的変数が共有されます。それらをローカル変数にすることができれば、たとえ静的メソッドに対してローカルであっても、独自のスタックフレームを取得し、スレッドセーフであることになります。また、静的変数(ロックや他のマルチスレッドプログラミング手法など)を保護する場合、サンプル静的クラスをスレッドセーフにすることもできます。

第2に、あなたの例が変更する外部変数インスタンスを取り込まないか、または状態が別のスレッドによって影響を受ける可能性があるため、あなたの例は同様にスレッドセーフです。

+0

優れた情報ですが、ここで私が見つけたのはこれです。静的メソッドはローカル変数のみを使用する場合、スレッドセーフですか?乾杯。 –

+4

はい。ただし、静的なクラス変数ではなく、メソッドのローカル変数である必要があります。 (クラス変数はローカル変数と呼ばれることもあると思いますが、間違いかもしれません)。あなたは "ローカル変数のみを使用する"と言っているので、渡した変数の参照を割り当てていないことを暗示していますパラメータをローカル変数に追加します。 – Bill

関連する問題