开发者

Windows Forms Timer bug or bad use?

开发者 https://www.devze.com 2022-12-09 22:15 出处:网络
When programming a small OpenGL application using Windows Forms, I discovered something using a profiler that I thought was pretty wonky.

When programming a small OpenGL application using Windows Forms, I discovered something using a profiler that I thought was pretty wonky.

I'm using a System::Windows::Forms::Timer to detect a combination of mouse idling and some other user input. The tick functionality is useful, but on occasion I want to 'reset' the timer. You can't really do this directly, but you get the correct effect by doing this:

this->someTimer->Stop();
this->someTimer->Start();

The timer interval is 50ms. Sometimes my 'reset' code here is run every 30ms. To my surprise, this is a very tax开发者_开发知识库ing thing to do - 30% of my program execution is often in these two lines! And it isn't a case of calling these two lines too often. In certain contrived situations this code is called as often as OpenGLSwapBuffers() for example, but no more. I interpret this as meaning that these two lines cost roughly half as much my entire render loop!

Currently I'm using a workaround, but the timer method is a little more elegant. I'm very curious - why are these two lines so computationally expensive? What am I missing? Is there a better way to reset a timer?


Calling Start() and Stop() sets an internal "enabled" flag, which performs the following work every time it is set (in the case of Start) or unset (in the case of Stop):

public virtual void set_Enabled(bool value)
{
    lock (this.syncObj)
    {
        if (this.enabled != value)
        {
            this.enabled = value;
            if (!base.DesignMode)
            {
                if (value)
                {
                    if (this.timerWindow == null)
                    {
                        this.timerWindow = new TimerNativeWindow(this);
                    }
                    this.timerRoot = GCHandle.Alloc(this);
                    this.timerWindow.StartTimer(this.interval);
                }
                else
                {
                    if (this.timerWindow != null)
                    {
                        this.timerWindow.StopTimer();
                    }
                    if (this.timerRoot.IsAllocated)
                    {
                        this.timerRoot.Free();
                    }
                }
            }
        }
    }
}

As you can see, there is work involved, including handle allocation and management, which goes above and beyond simply setting an internal flag. This may be the expense of the issue you are seeing.

As a possible solution to your issue, I would like to call your attention to the fact that there are three timer implementations in the .NET Framework:

  • System.Timers.Timer
  • System.Threading.Timer
  • System.Windows.Forms.Timer

The System.Timers.Timer and the System.Threading.Timer implementations are lighter-weight implementations of timer functionality, and you should investigate whether one of those lighter implementations will be more performant and still meet the requirements of your project. For the differences in functionality between the implementations, please see this blog post from Mark Michaelis.

0

上一篇:

:下一篇

精彩评论

暂无评论...
验证码 换一张
取 消