Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Excessive CPU usage

I'm coping with a problem. In fact I need to use different timers in my programe and Timers from Framework .Net don't do what I expect. So I decided to create my own Timer, but my Timer uses too much CPU. This is my code :

using System;
using System.Threading;

namespace XXXXXXX.Common.Types
{
public delegate void TimerFinishedEventHandler(object sender, EventArgs e);

class Timer
{
    #region Attributes
    private long m_InitialTickCount;
    private long m_Interval;
    private Thread m_Thread;
    private bool m_Enabled;
    #endregion

    #region Events
    public event TimerFinishedEventHandler Finished;
    #endregion

    #region Constructors
    public Timer(long interval, TimerFinishedEventHandler e)
    {
        Finished += e;
        m_Interval = interval;
        Start(m_Interval);
    }
    #endregion

    #region Public methods
    /// <summary>
    /// Start the timer thread.
    /// </summary>
    public void Start(long interval)
    {
        m_Interval = interval;
        m_Enabled = true;
        m_InitialTickCount = Environment.TickCount;

        if (m_Thread == null)
        {
            m_Thread = new Thread(Check);
            m_Thread.Start();
        }
    }

    /// <summary>
    /// Stop the Timer.
    /// </summary>
    public void Stop()
    {
        m_Enabled = false;
    }

    /// <summary>
    /// Restart the Timer.
    /// </summary>
    public void Restart()
    {
        m_InitialTickCount = Environment.TickCount;
    }
    #endregion

    #region Private methods
    /// <summary>
    /// Check if the timer is finished or not.
    /// </summary>
    private void Check()
    {
        while (true)
        {
            if (!m_Enabled)
                return;

            if (Environment.TickCount > m_InitialTickCount + m_Interval)
            {
                OnFinished(EventArgs.Empty);
                return;
            }
        }
    }

    /// <summary>
    /// Called when the Timer is Finished.
    /// </summary>
    /// <param name="e">Event</param>
    protected virtual void OnFinished(EventArgs e)
    {
        if (Finished != null)
            Finished(this, e);
    }
    #endregion
}
}

Is there anybody who have a solution ? Because when I launch my program, 2 or 3 Timers are created, another thread run and I have my CPU 100% using.

like image 584
Veriditas Avatar asked Jul 09 '26 08:07

Veriditas


1 Answers

There is absolutely no reason you can't have multiple timers. I have programs that have hundreds of timers, and at any time a handful of them can be actually doing work. The point of timers is that they allow you to schedule periodic actions and not consume any CPU resources except when the actions are actually being processed. That is, if you set a timer to tick once per minute, then that timer doesn't occupy a thread, doesn't consume any memory (beyond a token amount for the timer handle and the callback address), and doesn't consume any CPU resources. Only when the timer "ticks" once per minute is a thread allocated to execute code for it. And typically that is a pool thread that already exists, so thread startup time is negligible.

Using a timer is very easy: you create a method for the timer to execute, and you schedule the timer to run it. For example:

System.Threading.Timer myTimer = 
    new System.Threading.Timer(MyTimerProc, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));

void MyTimerProc(object state)
{
    // do something here
}

You could have another timer that ticks every 30 seconds and executes a different timer proc:

System.Threading.Timer myOtherTimer = 
    new System.Threading.Timer(MyOtherTimerProc, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));

void MyOtherTimerProc(object state)
{
    // do something else here
}

The timers won't interfere with each other. Of course, if code in the timer procs modifies shared data (for example, both procs try to update a list or a dictionary), then you'll have to synchronize access to that shared data or use a concurrent data structure.

You can get into trouble with reentrancy if the processing in your timer proc takes longer than the timer period. If the processing in MyTimerProc takes longer than 60 seconds, then another timer tick can come along and now you have two threads executing that timer proc. That can cause many different types of problems if your code is not set up to handle it. Typically you eliminate that problem by making the timer a one-shot and restarting it at the end of each processing cycle. There are examples of doing that here on Stack Overflow.

System.Timers.Timer is a component wrapper around System.Threading.Timer. The idea that it's "optimized for high performance threading" or some such is silly. System.Timers.Timer gives you a familiar event-oriented interface, and also provides a SynchronizingObject, which lets you have the event raised on a particular thread rather than having to explicitly Invoke as you would with System.Threading.Timer. Typically, that's only useful in UI applications.

System.Timers.Timer has one particularly ugly "feature" that I consider a bug: it squashes exceptions. As the documentation says:

In the .NET Framework version 2.0 and earlier, the Timer component catches and suppresses all exceptions thrown by event handlers for the Elapsed event.

That behavior still exists in .NET 4.5. The problem is that if you have your Elapsed event:

private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
    // do stuff here
}

If your event handler throws an exception, it will propagate back to the timer code, which squashes the exception and never tells you about it. In effect, the timer does this:

try
{
    OnTimedEvent(source, args);
}
catch
{
    // Squash those pesky exceptions. Who needs them?
}

It's a bug hider because you never know that the exception was thrown. So your program doesn't work and you can't figure out why. It's for this reason that I strongly recommend that you NOT use System.Timers.Timer. Use System.Threading.Timer instead; after all, it's the base that System.Timers.Timer is built on.

like image 154
Jim Mischel Avatar answered Jul 11 '26 15:07

Jim Mischel



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!