C# 如何使用线程、计时器和控件来避免死锁
WindowsCE 5.0,NET Compact framework 3.5 我需要定期更新UI,所以我决定使用Threading.Timer。我的代码如下所示,除了在计时器的回调过程中出现Presenter.Stop()之外,它运行良好 调试输出表明它从UpdateViewSafe退出,并且Stop将始终在Monitor.Enter(同步)处等待。我的错在哪里?我尝试使用线程而不是计时器,但它也会在线程的回调时死锁,所以我猜锁定sync对象和Control.Invoke之间的某个地方会出现问题 源代码: 调试的输出: 我从来没见过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之间的某个地方会出现问
+++ Stop 2
我需要定期更新UI,所以我决定使用Threading.Timer
当您使用Winforms时,我建议您改用System.Windows.Forms.Timer
。它使用UI消息泵,因此代码在与UI相同的线程中执行,这意味着:
- 它是同步的
- 您不需要使用
来更新UI控件Invoke
旁注:使用
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