首页 > 解决方案 > C# Thread.Sleep() _PC 之间执行的其他时间

问题描述

我有个问题。

下面的源码是按下按钮时将面板向左和向右移动的线程。

但是,如果在开发 PC 上移动大约 1 秒,则在测试 PC 上大约需要 4 秒。

*测试 PC 的硬件性能更好。

我想知道为什么会出现这些结果。

 private void move()
    {
        while (Moving)
        {
            SlidePanel.BeginInvoke(new Action(() =>
            {
                if (SlideDirection == 0) // Left
                {
                    SlidePanel.Left -= 4;
                    if (SlidePanel.Left <= SystemSettingbtn.Left)
                    {
                        SlidePanel.Left = SystemSettingbtn.Left;

                        SystemPanel.BeginInvoke(new Action(() =>
                        {
                            SystemPanel.BringToFront();
                        }));

                        Moving = false;
                    }
                }
                else // Right
                {
                    SlidePanel.Left += 4;
                    if (SlidePanel.Left >= EnvSettingbtn.Left)
                    {
                        SlidePanel.Left = EnvSettingbtn.Left;

                        EnvironmnetPanel.BeginInvoke(new Action(() =>
                        {
                            EnvironmnetPanel.BringToFront();
                        }));

                        Moving = false;
                    }
                }
            }));

            Thread.Sleep(1);
        }
    }

标签: c#multithreadingwinformsruntimesleep

解决方案


这不是线程安全的。你需要以Moving某种方式同步。最简单的方法是使用lock.

有更有效的方法,但从这里开始学习是您最安全的选择。像这样的东西有效。

private readonly object movingLock = new object();
private bool _moving;
private bool Moving
{
    get { lock (movingLock) return _moving }
    set { lock (movingLock) _moving = value; }
}

关于为什么需要这样做的一个重要说明。 if (_moving)没有同步可以返回旧值。

您可以volatile在此处使用,但与流行的观点相反,它仍然不能保证读取最新值。


您将看到由于Thread.Sleep(1). 由内核来处理线程调度。它不保证那个时间。


我也不明白为什么你BeginInvoke已经在 UI 线程上。你可以Control.InvokeRequired用来检查。

如果你BeginInvoke已经在 UI 线程上会发生什么?

它不会立即执行。它被放置在消息队列中。该队列的大小也会增加显着的差异。

绘制消息在队列中的优先级较低。如果有要处理的消息会改变绘画,为什么还要费心绘画呢?所以这也耽误了绘画。


推荐阅读