.net System.Windows.Forms.Timer和实例变量
我有一个按钮点击事件处理程序,它更新包含表单中的私有、非共享实例变量 我还有一个System.Windows.Forms.Timer,它的勾选事件在按钮点击事件完成几秒钟后发生 我的问题是:勾选事件处理程序为什么有时(经常)看到该实例变量的前一个值?(我认为System.Windows.Forms.Timer对于实例变量是线程安全的。) 相关问题:这种情况在速度非常快的四处理器计算机上经常发生,但在速度较慢的双处理器上却很少发生,这与此相关吗?换句话说,这个问题是否可能与跨CPU同步实例变量有关 代码如下。为显示美观而修改注释约定.net System.Windows.Forms.Timer和实例变量,.net,event-handling,thread-safety,instance-variables,.net,Event Handling,Thread Safety,Instance Variables,我有一个按钮点击事件处理程序,它更新包含表单中的私有、非共享实例变量 我还有一个System.Windows.Forms.Timer,它的勾选事件在按钮点击事件完成几秒钟后发生 我的问题是:勾选事件处理程序为什么有时(经常)看到该实例变量的前一个值?(我认为System.Windows.Forms.Timer对于实例变量是线程安全的。) 相关问题:这种情况在速度非常快的四处理器计算机上经常发生,但在速度较慢的双处理器上却很少发生,这与此相关吗?换句话说,这个问题是否可能与跨CPU同步实例变量有关
/* Instance variable get/set */
Public Property mode() As modetype
Get
Return _mode
End Get
Set(ByVal value As modetype)
_mode = value
Select Case value
/* Lots of mode-specific processing here */
End Select
Debug.Assert(mode = value)
End Set
End Property
/* Click event handler */
Private Sub btnClear_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnClear.Click
Debug.Assert(Not (picVideo Is Nothing))
mode = modetype.clear
End Sub
/* Tick event handler */
Private Sub tmrCapture_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles tmrLiveImageCapture.Tick
// FOLLOWING LINE is where mode should be .clear but comes up as .live instead.
If mode = modetype.live Then
Debug.Assert(mode = modetype.live) // Seriously? Yes.
Try
execute_timer_tick_stuff()
Catch ex As Exception
/* Shouldn't happen */
tmrLiveImageCapture.Stop() // FIXME: can you stop a timer within its own tick event?
MessageBox.Show("Error in live timer tick: " & ex.Message)
Debug.Assert(Not tmrLiveImageCapture.Enabled)
End Try
End If
End Sub
谢谢。为了确保同一时间只执行一个代码块,请使用SyncLock。这将防止模式值在滴答声事件期间被捕捉 您需要一个唯一的引用类型实例作为组的键:
Dim TestSyncLock As New Object()
现在一次只能执行以下一个块:;其他的则等待整个同步锁块完成,然后另一个同步锁才有机会执行
SyncLock TestSyncLock
DoSomethingTricky()
End SyncLock
SyncLock TestSyncLock
DoSomethingElseTricky()
End SyncLock
一次不间断地执行整个代码块称为原子操作。为您的代码尝试以下操作:
Private modeSyncLock As New Object()
/* Instance variable get/set */
Public Property mode() As modetype
Get
Return _mode
End Get
Set(ByVal value As modetype)
/* If we have entered the tick handler's synclock, wait until it's done */
SyncLock modeSyncLock
_mode = value
End SyncLock
Select Case value
/* Lots of mode-specific processing here */
End Select
Debug.Assert(mode = value)
End Set
End Property
/* Click event handler */
Private Sub btnClear_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnClear.Click
Debug.Assert(Not (picVideo Is Nothing))
mode = modetype.clear
End Sub
/* Tick event handler */
Private Sub tmrCapture_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles tmrLiveImageCapture.Tick
/* If we have entered the mode set, wait until it's done before proceeding */
SyncLock modeSyncLock
If mode = modetype.live Then
Debug.Assert(mode = modetype.live) // Seriously? Yes.
Try
execute_timer_tick_stuff()
Catch ex As Exception
/* Shouldn't happen */
tmrLiveImageCapture.Stop() // FIXME: can you stop a timer within its own tick event?
MessageBox.Show("Error in live timer tick: " & ex.Message)
Debug.Assert(Not tmrLiveImageCapture.Enabled)
End Try
End If
End SyncLock
End Sub
可能有几件事。我们能看看你的密码吗?此外,timer tick事件由windows消息触发,并与button click事件在同一线程中执行,因此这不是多线程问题,而是大量代码。我添加了一个说明性子集。谢谢你的评论。我几乎认为你的按钮事件应该是MouseUp或KeyUp。这并不是说可以解决问题,因为我认为使用
定时器
可以很容易地看到时钟的差异。只是一个想法…我觉得你的帖子没有问题。我想知道你没有发布什么。在btnClear\u Click中,在开始执行任何可能导致execute\u timer\u tick\u stuff()失败的操作之前,是否设置了模式?有没有其他语句可以改变mode(或_mode)的值而你没有发布?不,这太疯狂了,jnm2!0您将看到整个btnClear\u单击。1. _仅在模式集方法中更改模式。2.模式本身由其他未触发的事件处理程序更改。最后,我应该说mode(_mode)值在Tick事件处理程序的执行过程中会被捕获。换句话说,Tick错误地看到mode=modetype.live,然后捕获mode=modetype.clear,稍微晚一点,有点随机。最后,这并没有真正解决我的问题。。。但这是一个很好的答案,也是唯一的官方答案,所以请享受一些声誉积分。谢谢,jnm2!