1

私は Thread.sleep を使用せずに次のことを行いたいと考えています。

Timer クラスを使用してみましたが、使い方が間違っているようです。

   func test()
 for(int i=0;i<100;i++){
      func A()
      wait for 20 seconds
      func B()
      wait for 45 seconds
      func C()
      wait for 2 mins
}//repeat for 100 times
4

2 に答える 2

2

Task フレームワークを探しているかもしれません。次のようなことができます。

async void Run()
{
    for (int i=0; i<100; i++)
    {
        A();
        await Task.Delay(TimeSpan.FromSeconds(20));
        B();
        await Task.Delay(TimeSpan.FromSeconds(45));
        C();
        await Task.Delay(TimeSpan.FromMinutes(2));
    }
}

関数はすぐに戻りますが、そのループはバックグラウンドで実行され続けます。

編集: svick が以下に示すように、これは .NET 4.5 の新しい機能です。

于 2013-02-24T19:24:42.043 に答える
0

私は行って大きな仮定を立てるつもりです (すべての手がかりはその方向を指しています):

これらすべてを Windows フォームで実行していて、Thread.Sleep() の呼び出し中に GUI がフリーズしないようにしたいと考えていますよね? その場合は、次のメソッドを記述できます。

public static class Foo {
  public static void MySleep(int milliseconds) {
    int startTick = Environment.TickCount;
    while (Environment.TickCount - startTick < milliseconds)
      Application.DoEvents();
  }
}

次に、Thread.Sleep 呼び出しを Foo.MySleep 呼び出しに置き換えます (ただし、コントロールがMySleep呼び出しの内部にある間にプロセス全体をもう一度実行できる Application.DoEvents の影響に注意してください。お勧めしません)。予防策を講じない場合は、この方法を使用してください。たとえば、終了しない再帰で何度も実行される可能性があるため、テストの実行中にfunc test()を呼び出すボタンを常に無効にする必要があります) :

func test()
  for(int i=0;i<100;i++){
    func A()
    Foo.MySleep(20 * 1000);
    func B()
    Foo.MySleep(45 * 1000);
    func C()
    Foo.MySleep(2 * 60 * 1000);
}//repeat for 100 times

それを行う別の (少し安全な) 方法があります。これには、セカンダリ スレッドといくつかの Control.Invoke 呼び出しが含まれます。また、標準の System.Thread.Sleep(int milliseconds) メソッドを使用することもできます。

そして、それは次のようになります:

public class Form1 : Form {

  public void triggerTestAndReturnImmediately() {
    new Thread(start: () => {

      Action callA = () => funcA();
      Action callB = () => funcB();
      Action callC = () => funcC();

      for(int i=0;i<100;i++){
        this.Invoke(callA);
        Thread.Sleep(20 * 1000);

        this.Invoke(callB);
        Thread.Sleep(45 * 1000);

        this.Invoke(callC);
        Thread.Sleep(2 * 60 * 1000);
      }//repeat for 100 times


    }).Start();
  }

}

「this.Invoke( someDelegate )」ビットは、メソッド「triggerTestAndReturnImmediately」が Form サブクラスのメンバーであり、「this」が Form インスタンスであるという事実に基づいています。

ここで行われているのは、待機操作と実際のワーカー (funcA、funcB、funcC) のトリガーを別のスレッドで実行することです。実際のワーカー自体ではなく、実際のワーカーの trigerring のみを実行するのはなぜですか? これらの func から GUI オブジェクトにアクセスする可能性が高く、WinForms (および他の多くの .NET または非 .NET GUI フレームワーク) では許可されていないためです。

したがって、GUI スレッド (質問で指摘したように) は、これらの関数を実行するために 99% の時間で自由でなければならないことを求めています。したがって、 this.Invoke ( someDelegate ) の呼び出しです。

先に述べたのと同じ予防措置を講じる必要がありますが、それはすべてあなた次第であり、アプリケーションに何をさせたいかによって異なります。ボタンの Click イベント ハンドラーでtriggerTestAndReturnImmediatelyを呼び出し、プロセス中に無効にしたい場合、ボタンを無効にして再度有効にするにはどうすればよいでしょうか?

これを行う場合:

void buttonBar_Click(object sender, EventArgs e) {
  this.buttonBar.Enabled = false;
  this.triggerTestAndReturnImmediately();
  this.buttonBar.Enabled = true;
}

なぜなら、triggerTestAndReturnImmediatelyメソッドは、その名前が示すとおり「すぐに戻る」ためです。

では、どうやってこれをやってのけるのですか?次のようなことができます:

void buttonBar_Click(object sender, EventArgs e) {
  this.triggerTestAndReturnImmediately();
}


  public void triggerTestAndReturnImmediately() {
    this.buttonBar.Enabled = false;

    new Thread(start: () => {

      Action callA = () => funcA();
      Action callB = () => funcB();
      Action callC = () => funcC();
      Action reenableButton = () => this.buttonBar.Enabled = true;

      for(int i=0;i<100;i++){
        this.Invoke(callA);
        Thread.Sleep(20 * 1000);

        this.Invoke(callB);
        Thread.Sleep(45 * 1000);

        this.Invoke(callC);
        Thread.Sleep(2 * 60 * 1000);

        this.Invoke(reenableButton);
      }//repeat for 100 times


    }).Start();
  }

また、呼び出しシーケンスがクラッシュするかどうかにかかわらず、try finallyステートメントまたはその他の体操を使用して、常にボタンを再度有効にしてください。

したがって、私が話していた予防策が何であるかを理解できると思います (アプリに何をさせたいかによって異なります)。

于 2013-02-24T19:24:02.093 に答える