2

System.Threading.Timer を開始するアプリを開発しています。これは、シリアル ポートに対してかなり高速な読み取り/書き込みを行います (100 ミリ秒ごと)。タイマーのコールバック メソッドは次のようになります。

if (_timerTaskRunning)
{
    Debug.WriteLine("still running");
    return;
}

_timerTaskRunning = true;

... do the serial write/read here ...

_timerTaskRunning = false;

_timerTaskRunningフラグは、前のタイマー「サイクル」が終了していない場合、つまり 100 ミリ秒以上かかっている場合にデリゲートが実行されないようにするための安全策です。

アプリを初めて起動すると、ifステートメントから約 10 個のデバッグ メッセージが表示されます。その後落ち着きますが、7 ~ 8 秒後に別のメッセージのグループが表示されます。再び落ち着いて、ときどきメッセージのグループがさまざまな数で表示されるのを目にします。

メッセージの最初のグループは、アプリがまだ起動しているため、オブジェクト/UIの初期化などのためにタイマーデリゲートの実行が遅いことが原因であると想定していますが、後続のメッセージは、ガベージコレクションが頻繁に開始され、速度が低下していることが原因である可能性がありますダウン?「モック」シリアルポートでも同じ動作が見られるため、シリアルポートではありません。

タイマーの最初の実行を数秒遅らせてみましたが、違いはありません。タイマーが開始してから最初の 1 秒ほどの間、デバッグ メッセージのバッチが表示されます。タイマー タスクのいくつかをスキップすることは世界の終わりではありませんが、何が原因であるかを知ることは興味深いでしょう。原因をさらに調査するために私にできることはありますか? まだ使ったことがないのですが、おすすめのカウンターを教えてください。

4

2 に答える 2

3

再入可能性に問題があるようです。基本的に、あなたの _timerTaskRunning は、おそらく競合状態が原因でセーフガードとして機能していません。

  1. System.Threading.Timerの代わりに System.Timers.Timerを使用する
  2. Timer.AutoReset を false に設定します。これにより、明示的に必要になるまで折り返し電話をかけないため、魅力的な問題が解決されます。
  3. タイマーを再度実行する必要がある場合は、タイマーで Start() を呼び出します (実行時間を考慮して間隔を調整する必要がある場合があります)。

start を呼び出すことができる複数のスレッドがある場合は、呼び出しを同期する必要があります。

于 2012-06-26T15:43:59.967 に答える
2

あなた_timerTaskRunningはいくつかのスレッドによって更新されます。スレッドセーフにするには、ロックを使用する必要があります。

ただし、タイマーはまったく使用しません。ここでは、非リネットラント タイマーを実装しました。AutoResetEvent再入しないことを保証するタイムアウト付きの WaitOne を使用します。

于 2012-06-26T15:38:58.833 に答える