2

現時点では、Callaback プロシージャ内に For ループがあります。

private void InitializeComponent()
{

var timer = new System.Threading.Timer(TimerProc, null, 60000, 60000);

}

public void TimerProc(object state)
{

    for (int i = 0; i <= 6; i++)
    {
        //Do something here
    }

}

TimerProc は、60000 ミリ秒ごとに繰り返すように設定しているにもかかわらず、1 回しか起動しません。ループ内の操作は、最初の完了後に実行されなくなったようです。

ただし、For ループを削除して、コンソール ラインへの出力やテキスト ファイルへの書き込みなどの他のアクションを実行すると、TimerProc は期待どおりに繰り返されます。

これはなぜですか? また、Callback プロシージャ内のループが最初の起動後に実行を停止するのはなぜですか?

while(true) 無限ループを使用し、Thread.Timer を使用して x ミリ秒後にプロセスを一時停止することで回避策を作成しました。

while ループを使用した新しい vised コードは次のようになります。

private void InitializeComponent()
{

processthread = new Thread(new ThreadStart(DoSomething));
processthread.Start();

}

public void DoSomething()

{

  while(true)
  {
    for (int i = 0; i <= 6; i++)
    {
           //do something here

    }
    Thread.Sleep(5000);
  }

}

System.Thread.Timer のコールバック プロシージャがループを処理できない理由を知りたいだけです。

乾杯、

スタンリー

4

2 に答える 2

1

質問に含めたコードから、どこtimerにも参照を保存していないようです。私は間違っている可能性がありますが、タイマー オブジェクト自体がガベージ コレクションされているため、コールバックが繰り返されていないと推測されます。タイマーへの参照を長寿命の変数 (つまり、フィールド) に割り当てれば、問題を解決できると思います。

言い換えれば、forループはあなたが見ているものとは何の関係もないと思います (私は証拠に異議を唱えているのではなく、それが偶然であり、他には何もないと提案しているだけです)。

私の仮説を検証するために、次の非常に単純な Windows フォーム アプリを作成しました。

using System;
using System.Threading;
using System.Windows.Forms;

using Timer = System.Threading.Timer;

public class Program
{
    static void Main(string[] args)
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new TestForm());
    }
}

class TestForm : Form
{
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        var timer = new Timer(TimerProc, null, 1000, 1000);
    }

    public void TimerProc(object state)
    {
        for (int i = 0; i <= 6; i++)
        {
            Console.WriteLine(DateTime.Now.ToLongTimeString());
        }
    }
}

30 秒強の間、現在の時刻がコンソールに表示されるのを見ました。それからそれは止まりました。

対照的に、次の変更は問題を解決するようです。

class TestForm : Form
{
    // Note: declare a field to store a reference to the timer.
    Timer timer;

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        this.timer = new Timer(TimerProc, null, 1000, 1000);
    }

    // ...
}

上記の変更を行った後、プログラムを再度開始しましたが、タイマーが数分間作動し続けました。

于 2012-07-23T04:06:08.307 に答える
0

更新: Dan Taoとの議論の後、参照がないため、おそらく GC の問題です。参照を追加すると問題が解決します [8 行目と 20 行目のコメントを外します]。質問に「forループ」が存在すると、おそらくコレクションが発生しました。おそらく、この特定のインスタンスで、それを削除してより単純なLOCに置き換える理由を説明するガベージを生成することによるものです。

using System;
using System.Threading;

namespace SO_TimerTroubles
{
    class Program
    {
        //static Timer t;
        static void Main(string[] args)
        {
            StartTimer();  //Works fine.
            Console.WriteLine("Press Enter to BeginGC");
            Console.ReadLine();
            GC.Collect();  //Timer stops.
            Console.ReadLine();
        }

        public static void StartTimer()
        {
            //t =
            new Timer(TimerProc, null, 1000, 1000);
        }

        static public void TimerProc(object state)
        {
            Console.WriteLine("Timer Called");
            for (int i = 0; i < 5; i++)
            {
            }
        }
    }
}

[元の回答] 以下は正常に動作します - エラーは別の場所にあると思われます。

class Program
    {
        static void Main(string[] args)
        {

            var timer = new Timer(TimerProc, null, 1000, 1000);

            Console.ReadLine();
        }

        static public void TimerProc(object state)
        {
            Console.WriteLine("Called");
            for (int i = 0; i <= 6; i++)
            {
                Console.WriteLine(i);
            }

        }
    }
于 2012-07-23T04:06:19.613 に答える