2009-05-02 10 views
12

私は、経過イベントハンドラを同時に処理しないタイマーがあります。しかし、1つのElapsedイベントを処理すると、が他と干渉する可能性があります。私は以下のソリューションを実装しましたが、何かが間違っていると感じました。別の方法でタイマーを使用するか、スレッド空間内の別のオブジェクトを使用する必要があります。定期的に状況を確認する必要があるため、タイマーが最も適しているように見えましたが、時にはチェックが私の時間より長くかかることがあります。これはこれに最も近いアプローチですか?経過イベントの処理中にタイマーをブロックする方法はありますか?

// member variable 
private static readonly object timerLock = new object(); 
private bool found = false; 


// elsewhere 
timer.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds; 
timer.Elapsed = Timer_OnElapsed; 
timer.Start(); 


public void Timer_OnElapsed(object sender, ElapsedEventArgs e) 
{ 
    lock(timerLock) 
    { 
    if (!found) 
    { 
     found = LookForItWhichMightTakeALongTime(); 
    } 
    } 
} 
+2

これはコミュニティのWikiであってはいけません。 – Samuel

+0

@Samuel - ポスターの希望があれば、どんな質問もコミュニティウィキになることがあります。 FAQは、いくつかの質問が最初からコミュニティwikiでなければならないことを明記していますが、CWをどのような質問にも適用することを制限しません。 – tvanfosson

+1

@tvanfosson:私は彼に、これらのような質問はコミュニティのwikiであってはならないことを知らせていました。 – Samuel

答えて

13

AutoResetをfalseに設定してから、タイマーを処理した後に明示的にリセットすることができます。もちろん、それをどのように処理するかは、タイマーがどのように動作するのかによって異なります。このようにすると、実際の指定された間隔からタイマーを離れることができます(停止と再起動のように)。あなたのメカニズムは各インターバルを起動させて処理することができますが、ハンドラを起動させるタイマーの満了付近で未処理のイベントのバックログが処理される可能性があります。 LookForItWhichMightTakeALongTime()は長い時間がかかるとしている場合

timer.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds; 
timer.Elapsed += Timer_OnElapsed; 
timer.AutoReset = false; 
timer.Start(); 


public void Timer_OnElapsed(object sender, ElapsedEventArgs e) 
{ 
    if (!found) 
    { 
     found = LookForItWhichMightTakeALongTime(); 
    } 
    timer.Start(); 
} 
+0

AutoResetとElapsedは、UI作業に対して安全ではないSystem.Threading.Timer用です。 – Samuel

+0

@Samuel - Elapsedは、OPが使用しているイベントです。おそらく、これはWinFormsアプリケーションではありません。 – tvanfosson

8

私は通常、処理中にタイマーを停止し、try/finallyブロックを入力し、完了したらタイマーを再開します。

0
timer.enabled = false 

または

timer.stop(); 

timer.enabled = true 

または

timer.start(); 
-1

私はそう

ようSystem.Threading.Timerを使用10
class Class1 
    { 
     static Timer timer = new Timer(DoSomething,null,TimeSpan.FromMinutes(1),TimeSpan.FromMinutes(1)); 

     private static void DoSomething(object state) 
     { 
      timer = null; // stop timer 

      // do some long stuff here 

      timer = new Timer(DoSomething, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); 
     } 



    } 
+1

終了時には常にタイマインスタンスを破棄する必要があります。 –

+0

ガーベッジコレクタがクリーンアップしていない限り、タイマーはコールバックメソッドを起動し続けます。予期しない非決定論的な影響が生じる可能性があります。 –

1

が、私はそうすることがあなたのUIスレッドをロックし、ユーザーが自分のアプリケーションがフリーズしていると考え殺す可能性があるためSystem.Windows.Forms.Timerを使用していないお勧めします。

あなたが使用できるものはBackgroundWorker(必要に応じてTimerと一緒に)です。

public class MyForm : Form 
{ 
    private BackgroundWorker backgroundWorker = new BackgroundWorker(); 

    public MyForm() 
    { 
    InitializeComponents(); 
    backgroundWorker.DoWork += backgroundWorker_DoWork; 
    backgroundWorker.RunWorkerCompleted += 
           backgroundWorker_RunWorkerCompleted; 
    backgroundWorker.RunWorkerAsync(); 
    } 

    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
    { 
    e.Result = LookForItWhichMightTakeALongTime(); 
    } 

    private void backgroundWorker_RunWorkerCompleted(object sender, 
              RunWorkerCompletedEventArgs e) 
    { 
    found = e.Result as MyClass; 
    } 
} 

そして、あなたが望むならあなたもTimerから、あなたがしたいどこからでもRunWorkerAsync()を呼び出すことができます。 RunWorkerAsync()が実行されているときに例外がスローされるので、BackgroundWorkerが既に実行されているかどうかを確認してください。

private void timer_Tick(object sender, EventArgs e) 
{ 
    if (!backgroundWorker.IsBusy) 
    backgroundWorker.RunWorkerAsync(); 
} 
関連する問題