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
のようにadditonal状態( "running"または "stopped")を保持する必要はありません。
(更新)は、以下の回答で@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;
}
}
}
このコードのアイデア、明確にするために、次のとおりです。
- チェックのシンプルかつ迅速な方法を持っています時間は、特定の操作/イベント経過した場合、
- 方法は、複数のスレッド、
- から呼び出された場合破損状態(等ユーザーの変更、NTP同期、時間帯、)OSクロック変化に鈍感でなければならないはず
私はこれまで、それは似て使用します。
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命令にJITされることさえあります。 – Lou
これまでのところ、QueryPerformanceCounterを自分で呼び出すのはなぜですか? –