4

I have a simple 'Working' form that runs on its own thread to keep the user informed that the application hasn't died during long running operations. In order to get the working form to update I had to insert a DoEvents() call.

I'm curious, will this only pump messages for the current thread I'm in, or will it do it for the whole application? I would prefer that the main window stay unresponsive till the operation finishes, so I'm curious as to the behavior. Below is the code for the working form.

Just to be clear, I'm fine with the code I have, but I would like to know how DoEvents() behaves with threads.

    Public Class frmWorking

    ''' <summary>
    ''' Creates and starts a new thread to handle the Working Dialog
    ''' </summary>
    ''' <returns>The thread of the Working dialog.</returns>
    ''' <remarks></remarks>
    Public Shared Function StartWait() As WorkingFromToken
        Dim th As New Threading.Thread(AddressOf ShowWait)
        Dim token As New WorkingFromToken
        th.Start(token)
        Return token
    End Function

    Private Shared Sub ShowWait(token As WorkingFromToken)
        Dim frm As New frmWorking
        Try
            frm.Show()
            Do
                If frm.txtWait.Text.Length > 45 Then
                    frm.txtWait.Text = "Working"
                Else
                    frm.txtWait.Text &= "."
                End If
                Windows.Forms.Application.DoEvents()
                Threading.Thread.Sleep(250)
            Loop While token.Running
            frm.Hide()

        Catch ex As Threading.ThreadAbortException
            Threading.Thread.ResetAbort()
            frm.Hide()
            Return
        End Try

    End Sub

End Class
Kratz
  • 4,180
  • 3
  • 30
  • 51
  • It is rarely a good idea to have multiple UI threads. – SLaks Jun 07 '11 at 14:46
  • Even in your controlled circumstances, `Abort` is dangerous and should be avoided. Polling a `cancelled` flag is much safer. – SLaks Jun 07 '11 at 14:48
  • @SLacks, I actually just changed it to this approach, I guess I just left the catch in there because I was unsure if anything else generated the ThreadAbortException, other than explicitly calling Thread.Abort. – Kratz Jun 07 '11 at 14:54
  • No; only `Abort()` will throw a `ThreadAbort`. – SLaks Jun 07 '11 at 15:09

2 Answers2

3

DoEvents will only pump the current UI thread.

However, I do not recommend your approach.

Instead, you should do your work on a background thread, and show a modal progress form on the UI thread and update it using BeginInvoke or a BackgroundWorker.

SLaks
  • 800,742
  • 167
  • 1,811
  • 1,896
  • What are the specific concerns with having multiple UI threads? Not that I don't trust you, but I like to know as much as I can. – Kratz Jun 07 '11 at 15:01
  • http://stackoverflow.com/questions/4793283/two-ui-thread-in-c-windows-application/4793854#4793854 – SLaks Jun 07 '11 at 15:08
  • It does seem a little strange to raise a GUI thread to report on long-running operations. It's much more usual to thread off these operations instead so that the application main thread can respond to UI messages. As for Application.DoEvents, I have never used such a thing in VB, C# or Delphi. Presumably, you need it here because you are looping in an event handler/WndProc of your seperate GUI thread?? – Martin James Jun 07 '11 at 15:21
2

DoEvents will only effect the thread from which it is called. It will dequeue all windows messages posted to that thread and dispatch them accordingly. After all messages have been dispatched it will return back to the caller.

I have a couple of other observations about your code though.

  • You have basically created your own crippled version of a message loop by calling DoEvents repeatedly in a loop. It would be better to just call Application.Run to initiate a full blown message loop.
  • Creating a message loop on a thread other than the main UI thread is rarely a good idea. There are some weird things that occur that are hard to deal with. For example, a modal dialog box from one thread could overlap a modal dialog box from another.
  • Attempting to catch a ThreadAbortException is pointless in most situation. If you ever get this exception then it is possible (perhaps even likely) that the state of the entire AppDomain has been corrupted. It is better to tear down the application domain than to try to gracefully deal with it. This is because the exception could be injected at any point during the execution of the thread and those injection points could be in the middle or a write, a lengthy operation, or otherwise some unsafe point.
  • As a corollary to the point above do not use Thread.Abort to terminate another thread. There are many too many things that can go wrong. It is better to cause the thread to end gracefully using safer mechanisms.
Community
  • 1
  • 1
Brian Gideon
  • 45,093
  • 12
  • 98
  • 145