C# 如何使用线程、计时器和控件来避免死锁

C# 如何使用线程、计时器和控件来避免死锁,c#,multithreading,winforms,timer,compact-framework,C#,Multithreading,Winforms,Timer,Compact Framework,WindowsCE 5.0,NET Compact framework 3.5 我需要定期更新UI,所以我决定使用Threading.Timer。我的代码如下所示,除了在计时器的回调过程中出现Presenter.Stop()之外,它运行良好 调试输出表明它从UpdateViewSafe退出,并且Stop将始终在Monitor.Enter(同步)处等待。我的错在哪里?我尝试使用线程而不是计时器,但它也会在线程的回调时死锁,所以我猜锁定sync对象和Control.Invoke之间的某个地方会出现问

WindowsCE 5.0,NET Compact framework 3.5

我需要定期更新UI,所以我决定使用Threading.Timer。我的代码如下所示,除了在计时器的回调过程中出现Presenter.Stop()之外,它运行良好

调试输出表明它从UpdateViewSafe退出,并且Stop将始终在Monitor.Enter(同步)处等待。我的错在哪里?我尝试使用线程而不是计时器,但它也会在线程的回调时死锁,所以我猜锁定sync对象和Control.Invoke之间的某个地方会出现问题

源代码:

调试的输出:

我从来没见过

+++ Stop 2
我需要定期更新UI,所以我决定使用Threading.Timer

当您使用Winforms时,我建议您改用
System.Windows.Forms.Timer
。它使用UI消息泵,因此代码在与UI相同的线程中执行,这意味着:

  • 它是同步的
  • 您不需要使用
    Invoke
    来更新UI控件
你不会有一个很好的精度(~50毫秒),但在大多数情况下,它应该足以用于UI更新


旁注:使用
lock(lockObject){…}
而不是
Monitor
(几乎相同,但随着关键部分范围的具体化而更易于使用)

因为我们没有看到如何调用
Start
Stop
,所以很难确切地告诉您如何获得所拥有的输出

很可能在
UpdateViewSafe
进入监视器之前调用并安排了
Stop
,但它没有获得时间片。这允许
UpdateViewSafe
执行到
Sleep
,此时上下文切换到运行
Stop
的线程,该线程向下执行到
监视器。在等待的位置输入
。此时,
UpdateViewSafe
再次开始运行

我也看不到您的其他输出,但我猜您会看到这些

+++ UpdateViewSafe 1
+++ UpdateViewSafe 2
+++ Stop 1
+++ UpdateViewSafe 3
+++ UpdateViewSafe 4
+++ Stop 2
尽管最后两行很有可能被交换,这取决于您最终在scheduler quantum中的方式。它肯定可以运行任何一种方式,所以不要依赖其中一种


如果要控制“停止1”输出,则它需要位于关键部分内-这就是关键部分的工作方式。

我更喜欢将更新逻辑放置在presenter中,而不是视图中。无论如何,我想知道我的代码哪里出了问题。他不主张将逻辑移到视图中。表单计时器在演示者中工作正常。
Start
Stop
正由用户调用
public MyForm(){InitializeComponent();presenter=new presenter(this);buttonStart.Click+=委托{presenter.Start();};buttonStop.Click+=委托{presenter.Stop();};}
在执行
UpdateViewSafe
期间,当出现
Stop
时,我从未看到
+++Stop 2
消息。即使只安排了一个计时器的计时,其工作方式也是相同的:timer=newtimer(UpdateViewSafe,null,0,Timeout.Infinite);在实际代码中没有
线程。Sleep(1000)
,这只是为了模拟情况。
+++ Stop 2
+++ UpdateViewSafe 1
+++ UpdateViewSafe 2
+++ Stop 1
+++ UpdateViewSafe 3
+++ UpdateViewSafe 4
+++ Stop 2