C# Thread.Sleep() _PC 之间执行的其他时间

Posted

技术标签:

【中文标题】C# Thread.Sleep() _PC 之间执行的其他时间【英文标题】:C# Thread.Sleep() _ Other time to perform between PCs 【发布时间】:2021-05-08 11:03:35 【问题描述】:

我有一个问题。

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

但是,如果在开发 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);
        
    
使用 [await Task.With Daly (1)] 我已经确认两种环境具有相同的运行时间。 感觉很奇怪 Thread.sleep(1) 在更好的环境中变慢了。

【问题讨论】:

可以发Moving的声明吗? @Zer0 我从线程中声明了布尔值。 [bool Moving = false] 和当按钮事件发生时改变 Moving = true -> 线程开始 【参考方案1】:

这不是线程安全的。您需要以某种方式同步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),您会看到差异。由内核来处理线程调度。它不保证那个时间。


我也不明白你为什么要在 UI 线程上执行 BeginInvoke。可以使用Control.InvokeRequired查看。

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

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

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

【讨论】:

您能否提供一个权威来源,为什么 volatile 不能解决这个问题?无论哪种方式,我都阅读过意见,但没有看到有关问题细节的良好来源。 @JonasH volatile 真正的意思是告诉编译器“不要优化这个”,因为许多编译器优化包括读写重新排序。这是一个深入的source。我不会称任何来源为“权威”,包括我自己。 您提供的链接表示,如果架构需要,访问 volatile 字段将发出栅栏。并且围栏应该足以确保该值是最新的。 IE。栅栏影响编译器和 CPU。所以我仍然不明白为什么 volatile 还不够。 @JonasH 不,它没有。我建议阅读整个页面。引用:“...文档指出,使用 volatile 关键字可确保该字段始终存在最新的值。这是不正确的...” Joe Duffy 编写了示例代码(他曾在Microsoft,写了一本关于并发的书,并且是 TPL 的领导者)。 对于那些想要像volatile 这样易于使用而没有陷阱的人,只需使用Thread.VolatileRead(和VolatileWrite)代替。

以上是关于C# Thread.Sleep() _PC 之间执行的其他时间的主要内容,如果未能解决你的问题,请参考以下文章

C# Task.Delay()和Thread.Sleep()有什么区别?

C#中的Task.Delay()和Thread.Sleep()区别

C# 中的 Thread.Sleep(1) 有啥影响?

C#中关于Thread.sleep(1000)的问题!!

c#中怎样建立定时器?用以替代thread.sleep(),克服sleep延时不精确的问题。

如何在 C# 中重新启动任务?或如何重新启动 Thread.Sleep()?