Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
591 views
in Technique[技术] by (71.8m points)

.net - System.Threading.Timer in C# it seems to be not working. It runs very fast every 3 second

I've a timer object. I want it to be run every minute. Specifically, it should run a OnCallBack method and gets inactive while a OnCallBack method is running. Once a OnCallBack method finishes, it (a OnCallBack) restarts a timer.

Here is what I have right now:

private static Timer timer;

private static void Main()
{
    timer = new Timer(_ => OnCallBack(), null, 0, 1000 * 10); //every 10 seconds
    Console.ReadLine();
}

private static void OnCallBack()
{
    timer.Change(Timeout.Infinite, Timeout.Infinite); //stops the timer
    Thread.Sleep(3000); //doing some long operation
    timer.Change(0, 1000 * 10);  //restarts the timer
}

However, it seems to be not working. It runs very fast every 3 second. Even when if raise a period (1000*10). It seems like it turns a blind eye to 1000 * 10

What did I do wrong?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This is not the correct usage of the System.Threading.Timer. When you instantiate the Timer, you should almost always do the following:

_timer = new Timer( Callback, null, TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite );

This will instruct the timer to tick only once when the interval has elapsed. Then in your Callback function you Change the timer once the work has completed, not before. Example:

private void Callback( Object state )
{
    // Long running operation
   _timer.Change( TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite );
}

Thus there is no need for locking mechanisms because there is no concurrency. The timer will fire the next callback after the next interval has elapsed + the time of the long running operation.

If you need to run your timer at exactly N milliseconds, then I suggest you measure the time of the long running operation using Stopwatch and then call the Change method appropriately:

private void Callback( Object state )
{
   Stopwatch watch = new Stopwatch();

   watch.Start();
   // Long running operation

   _timer.Change( Math.Max( 0, TIME_INTERVAL_IN_MILLISECONDS - watch.ElapsedMilliseconds ), Timeout.Infinite );
}

I strongly encourage anyone doing .NET and is using the CLR who hasn't read Jeffrey Richter's book - CLR via C#, to read is as soon as possible. Timers and thread pools are explained in great details there.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...