How to update the UI inside the Threadpool?

ricky.haropohop

New member
Joined
Jun 6, 2012
Messages
2
Programming Experience
5-10
Hi, I am currently working on a project that requires threadpool to simultaneously process a data.
My problem is that if I place a UI delegate inside the threadpool the system hangs. My plan for the
UI delegate is to display the status (Start/Finished) of the threadpool. I am using a wait handle to
synchronized the main thread and the thread pool. Also if i enabled the UI delegate and comments the
wait handle, UI is updated during process. Please help me on my program logic? Below is the code used
on my project. Thank you in advance.


VB.NET:
Imports System.Threading

Public Class FrmExample2


    Delegate Sub updatedisplay(ByVal txtdisplay As String)


    Public Class Fibonacci
        Private _n As Integer
        Private _fibOfN As Integer
        Private _doneEvent As ManualResetEvent
        Private _lstbox As ListBox

        Public Sub settextbox(ByVal txtdisplay As String)
            If _lstbox.InvokeRequired Then
                _lstbox.Invoke(New updatedisplay(AddressOf settextbox), New Object() {txtdisplay})
            Else
                _lstbox.Items.Insert(0, txtdisplay)
            End If
            Application.DoEvents()
        End Sub
        Public ReadOnly Property N() As Integer
            Get
                Return _n
            End Get
        End Property

        Public ReadOnly Property FibOfN() As Integer
            Get
                Return _fibOfN
            End Get
        End Property

        Sub New(ByVal n As Integer, ByVal doneEvent As ManualResetEvent, ByRef lstbox As ListBox)
            _n = n
            _doneEvent = doneEvent
            _lstbox = lstbox
        End Sub

        'Wrapper method for use with the thread pool
        Public Sub ThreadpoolCallback(ByVal threadcontext As Object)
            Dim threadindex As Integer = CType(threadcontext, Integer)
            'settextbox is used for updating the display inside the thread pool
            'THE SYSTEM HANGS WHEN THE UI DELEGATE settextbox are uncommented
            'settextbox(String.Format("thread {0} started...", threadindex))
            _fibOfN = CALCULATE(_n)
            'settextbox(String.Format("thread {0} result calculated....", threadindex))
            Application.DoEvents()
            _doneEvent.Set()
        End Sub

        Public Function CALCULATE(ByVal n As Integer) As Integer
            If n <= 1 Then
                Return n
            End If
            Return CALCULATE(n - 1) + CALCULATE(n - 2)
        End Function
    End Class


    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Const fibonacciCalculations As Integer = 20 '0 to 9

        'One event is used for each fibonacci object
        Dim doneEvents(fibonacciCalculations) As ManualResetEvent
        Dim fibarray(fibonacciCalculations) As Fibonacci
        Dim r As New Random

        'Set maximun thread to run simultaneously
        ThreadPool.SetMaxThreads(5, 200)

        'Configure and start threads using threadpool
        ListBox1.Items.Insert(0, String.Format("launching {0} tasks...", fibonacciCalculations))
        Application.DoEvents()

        For i As Integer = 0 To fibonacciCalculations
            doneEvents(i) = New ManualResetEvent(False)
            Dim f = New Fibonacci(r.Next(20, 40), doneEvents(i), ListBox1)
            fibarray(i) = f
            ThreadPool.QueueUserWorkItem(AddressOf f.ThreadpoolCallback, i)
        Next

        'wait for all threads in pool to calculate
        'WaitHandle.WaitAll(doneEvents)

        ' Wait for all threads in pool to calculation...
        For Each handle As WaitHandle In doneEvents
            handle.WaitOne()
        Next


        ListBox1.Items.Insert(0, "All calculations are complete.")
        Application.DoEvents()

        'Display the results.
        For i As Integer = 0 To fibonacciCalculations
            Dim f As Fibonacci = fibarray(i)
            ListBox1.Items.Insert(0, String.Format("Fibonacci({0}) = {1}", f.N, f.FibOfN))
            Application.DoEvents()
        Next

        MessageBox.Show("Test completed")
    End Sub
End Class
 
You should pretty much never be using a WaitHandle on the UI thread. A WaitHandle will cause the current thread to wait until another thread signals it to continue. You pretty much never want the UI thread to be waiting. Here's a simple example that will perform a number of tasks using the ThreadPool and notify the user of the progress and when done without any freezing of the UI and no need to call Application.DoEvents:
Imports System.Threading

Public Class Form1

    Private totalTaskCount As Long
    Private completedTaskCount As Long

    Private rng As New Random

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        totalTaskCount = 100
        completedTaskCount = 0

        For i = 1 To totalTaskCount
            ThreadPool.QueueUserWorkItem(AddressOf PerformTask)
        Next
    End Sub

    Private Sub PerformTask(dummy As Object)
        'Simulate a time-consuming operation.
        Thread.Sleep(rng.Next(2000, 5000))

        Interlocked.Increment(completedTaskCount)

        BeginInvoke(New MethodInvoker(AddressOf UpdateUI))
    End Sub

    Private Sub UpdateUI()
        Dim completedTaskCount = Interlocked.Read(Me.completedTaskCount)

        Label1.Text = completedTaskCount & " tasks completed"

        If completedTaskCount = totalTaskCount Then
            MessageBox.Show("All tasks completed")
        End If
    End Sub

End Class
You can test that out for yourself on a form with a Button and a Label.
 
Back
Top