views:

64

answers:

2

Hello,

I have this situation: a Form with a System.Timer in it (with AutoReset = False). The form has its main thread and the timer its own thread too (nothing new here).

When the user press a button I need to stop the timer, wait until the timer thread has stopped its execution and do something more.

On the other side, the timer updates an item at the form so BeginInvoke is used. The code looks like this:

Button Code:

 Private Sub ButtonStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonStop.Click
        SyncLock (m_stopLock)
            m_stopProcessTimer = True
            Threading.Monitor.Wait(m_stopLock)
        End SyncLock
        ''#Do more things here after the timer has end its execution and is stopped
    End Sub

Timer code:

Private Sub m_processTimer_Elapsed(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_processTimer.Elapsed
    Dim auxDelegate As EventHandler

    SyncLock (m_stopLock)
        If Not m_stopProcessTimer Then
            If Me.InvokeRequired Then
                auxDelegate = New EventHandler(AddressOf m_processTimer_Elapsed)
                Me.BeginInvoke(auxDelegate, New Object() {sender, e})
            Else
                DoFormStuf()
                m_processTimer.Start()
            End If
        Else
            Threading.Monitor.Pulse(m_stopLock)
        End If
    End SyncLock
End Sub

The point is that I wait the main thread to let the timer thread to end its work.

The problem is that this code deadlocks when the user clicks the button when the BeginInvoke is going to be called. How a simple thing like this one can be done? Looks like I cannot find a good solution to this problem :(

+2  A: 

Don't use locks at all, just make sure to do everything on the UI thread, and you can guarantee that nothing will be corrupted. Remember that dispatcher items run on the UI thread, so you know that if you're doing everything either in a dispatcher item or an event handler, only one thing is executing at a time.

Paul Betts
Sorry, I updated the button handler to show that I need to wait the timer execution ends and is stopped (it wont execute again) and after that do something.
SoMoS
Don't "wait", just have the UI do nothing, and have the Timer fire the dispatcher item to finish the rest. You can't block in a UI thread anyways, or else the UI will hang.
Paul Betts
Ok, now I see your point. It's a sort of callback called from the timer code isn't it?
SoMoS
Exactly, imagining what a message loop does helps:1. Reads the dispatcher queue, executes all the items2. Handles window messages3. Draws the window4. Goto #1
Paul Betts
A: 

1) Perhaps a little more code would be helpful. Do you create a new thread and put the timer ON that thread?

2) Have you tried using ManualResetEvent (.WaitOne() and .Set() instead?)

3) In your event, if invoke is required, you are re-calling your event again. Confusing...

4) Are you supposed to wait until the other thread is done? Then Thread.Join()?

Andrew Backer
1) Timers raise events on a new thread always.2) I think I will have the same lock with ManualResetEvent3) As far as I know is the normal way to handle with non UI threads that need to update UI items.4) Is not a thread that I created, is the internal Thread that the timer creates.
SoMoS