web-dev-qa-db-ja.com

メソッドが再度実行される前に実行が終了することを確認する方法

私は新しく、何かを理解しようとしています。イベントが発生したとき、またはタイマーが作動したときにメソッドを実行する単純なプログラムがあります。メソッドが完了するまでに5秒かかるとしましょう。その5秒間にイベントが発生する可能性があります。 すでに実行中にメソッドが呼び出されないようにするために何を使用/実行しますか?

それとも、メソッドが完了するまで実行されないので、単純なプログラムでは心配する必要がないものでしょうか?

少し背景と例。私はSystem.Windows.Forms.Timerを使用していますが、スレッドなどは何も使用していません。タイマーを備えた単純なWindowsフォームアプリケーション、処理を行うメソッド、および2つのイベントハンドラーを持っています。

Program{
  public Program(){
    DoSomething();
    Event.EventHappened += HandleEvent;
  }
  void DoSomething(){
    MyTimerVariable.Stop();
    InitMyTimer();
    //Just do something check network, access db write line, something
    //that in this example takes 5 secs for example purposes
    MyTimerVariable.Start();
  }
  void HandleEvent(){
    DoSomething();
  }
  void InitMyTimer(){
    // Create Timer, and add Timer tick event
  }
  void TimerTickedEvent(){
    DoSomething();
  }
}

私はそのプログラムからいくつかのものを残しましたが、それがいかに単純であるかを示すことを試みていました。 「DoSomething()」を実行している最中にイベントがトリガーされた場合、2つの「DoSomething()」メソッドを実行したくないので、もっと効率的にすることを考えていました。

2
RWhiten

これはSystem.Threading.Timerの代わりにSystem.Windows.Forms.Timerを使用しているため、イベントはUIスレッドで実行されるため、順序どおりに実行されることはありません。

ただし、スレッド化を使用している場合は、private object lockObject = new object();を作成してDoSomething()メソッドでロックするだけで、DoSomethingの本体が完了するまで実行されないことを確認できます。

5
Stephen

コードスタイルについては、@ theficusに同意する必要があります。

ただし、実装の詳細は含まれていません。

私は、彼の種類のboolean-check-implementationを使用した場合にのみ、複数のスレッドがコードブロックに入るケースを数多く経験しました。想定された不可能が実際に起こったので、あらゆる種類の混乱と混乱を引き起こします。ほとんどの場合にのみ機能し、常に機能するわけではない、あらゆる種類のスレッドロックアルゴリズムは、IMHOには無意味です。

この使用例のInterlocked。* APIは、boolean-check-implementationと同じくらい簡単で、1つのスレッドのみがコードブロックに入り、他のすべてのスレッドが続行することを確実にします。

private int isBusy = 0;

private void MyWorkerMethod()
{
  if(System.Threading.Interlocked.CompareExchange(ref this.isBusy, 1, 0) == 1)
  {
    return;
  }

  try
  {
    // do stuff
  }
  finally
  {
    this.isBusy = 0;
  }
}
3
TiltonJH

本当の目的が、同時に複数のワーカーメソッドが動作しないようにすることである場合、最も簡単な方法は次のようになります。

bool isBusy = false;
void MyWorkerMethod()
{
  if(isBusy == true)
  {
    return;
  }

  try
  {
    isBusy = true;
    // do stuff
  }
  finally
  {
    isBusy = false;
  }
}

このように、タイマーが刻むたびに、メソッドは引き続き実行されますが、最小限の手間で作業している場合、メソッドはすぐに終了します。ロックを使用すると、ロックが解放されるのを待っている状態でスタックが発生するため、スレッドの競合が発生します。

非常に偏執的である場合は、Interlocked。* APIを調べて、ワーカーが2回以上実行されていないことを疑いの余地なく確認することもできますが、ここではやりすぎかもしれません。

2
theficus