Threading problem

lbytesxk

Member
Joined
May 7, 2008
Messages
5
Programming Experience
3-5
Hi,
I have a problem, this is a simple code, where I want to display a form to the user on its own thread so that the main form remains responsive.
The problem is that the main form is not responsive, and when I try to debug it, the execution hits the stepThread.Join() line before the function that stepThread.Start() called has finished. I thought the Join would suspend the calling thread until the second thread finished.
Here is the code
VB.NET:
Imports System
Imports System.Threading
Imports CollectionLibrary
Imports System.Reflection
Namespace BEITestSteps
    Public Class TestEngine

        Private m_pass As Boolean
        Private m_testMessage As String = String.Empty
        Private m_startTime As DateTime
        Private m_stopTime As DateTime
        Private paramObject() As Object
        Private m_currentIndex As Integer
        Private currentParam As String
        Private currentParam1 As String
        Private currentParam2 As String
        Private currentParam3 As String
        Private currentParam4 As String
        Private currentParam5 As String
        Private currentFunc As String
        Private m_nextIndex As Integer
        Private Shared lastStepResult As Boolean
        Private tstSteps As CollectionLibrary.CollectionLib.TestSteps
        Public Sub New()

        End Sub
#Region "properties"
        Public ReadOnly Property Pass() As Boolean
            Get
                Return m_pass
            End Get

        End Property

        Public ReadOnly Property TestMessage() As String
            Get
                Return m_testMessage
            End Get
        End Property

        Public ReadOnly Property StartTime() As DateTime
            Get
                Return m_startTime
            End Get
        End Property

        Public ReadOnly Property StopTime() As DateTime
            Get
                Return m_stopTime
            End Get
        End Property

        Public ReadOnly Property NextIndex() As Integer
            Get
                Return m_nextIndex
            End Get
        End Property

        Public ReadOnly Property CurrentIndex() As Integer
            Get
                Return m_currentIndex
            End Get
        End Property     

        Public Property ParameterObject() As Object
            Get
                ParameterObject = paramObject
            End Get
            Set(ByVal Value As Object)
                paramObject = Value
            End Set
        End Property
#End Region

        Public Event StepCompleted()
        Private Delegate Function ExeInstruction(ByVal p1 As String, ByVal p2 As String) As Object

        Public Sub ExecuteTestStep(ByVal iStep As Integer, ByVal tstSteps As CollectionLibrary.CollectionLib.TestSteps)

            If tstSteps Is Nothing Then tstSteps = New CollectionLibrary.CollectionLib.TestSteps
            currentFunc = tstSteps.Item(m_currentIndex).FunctionName
          
            currentParam1 = tstSteps.Item(m_currentIndex).Param1
            currentParam2 = tstSteps.Item(m_currentIndex).Param2
            currentParam3 = tstSteps.Item(m_currentIndex).Param3
            currentParam4 = tstSteps.Item(m_currentIndex).Param4
            currentParam5 = tstSteps.Item(m_currentIndex).Param5

            Dim stepThread As New Thread(AddressOf _ExecuteTestStep)
            m_currentIndex = iStep
            stepThread.Start()

            stepThread.Sleep(500)       
            stepThread.Join()
        End Sub

        Private Sub _ExecuteTestStep()

            Try

            tstSteps.Item(m_currentIndex).Param1
                Dim gTsteps As GenericTestSteps = New GenericTestSteps
                Dim result As Object

                Dim myDel As ExeInstruction       
                myDel = AddressOf gTsteps.Instruction
                result = myDel.Invoke(currentParam1, currentParam2)           

                If Not result.GetType() Is Type.GetType("System.Boolean") And Not result.GetType() Is Type.GetType("System.Int32") Then
                    m_pass = False
                ElseIf result.GetType() Is Type.GetType("System.Boolean") Then
                    lastStepResult = CType(result, Boolean)
                    m_pass = lastStepResult
                    m_nextIndex += 1
                ElseIf result.GetType() Is Type.GetType("System.Int32") Then
                    If m_nextIndex > 2 Then m_nextIndex -= 2
                    lastStepResult = True
                    m_pass = lastStepResult
                ElseIf result.GetType() Is Type.GetType("System.Object") Then
                    If result.GetType() Is Type.GetType("System.Int32") Then
                        If m_nextIndex > 2 Then m_nextIndex -= 2
                        lastStepResult = True
                        m_pass = lastStepResult
                    ElseIf result.GetType() Is Type.GetType("System.Boolean") Then
                        lastStepResult = CType(result, Boolean)
                        m_pass = lastStepResult
                    End If
                End If
            Catch ex As Exception
                MsgBox(ex.ToString)
            End Try

        End Sub
    End Class
End Namespace

Here is the code that calls the second form, not the main form but that one that I want to thread separately
VB.NET:
Public Class GenericTestSteps
 Public Function Instruction(ByVal inString As String, ByVal param2 As String) As Object
            Dim instr As frmInstruction = New frmInstruction
            Dim result As Object = False
            instr.Init(inString)
            Dim displayThread As Thread
            displayThread = New Thread(AddressOf instr.Run)
            displayThread.Start()
            While instr.ISDONE <> True
                Thread.Sleep(25)
            End While
            result = instr.RPLY
            If result.GetType Is Type.GetType("System.Boolean") Then
                instr.Close()
                displayThread.Join()
                instr.Dispose()
                Return result
            ElseIf result.GetType Is Type.GetType("System.Int32") Then
                instr.Close()
                displayThread.Join()
                instr.Dispose()
                Return result
            End If
        End Function
End Class
 
This is where it gets funky. Any thread that creates a Windows GUI object becomes responsible for the message queue and pump that windows sets up to handle windowing messages to that window. This means if, for any reason, your thread finishes and dies, the message pump will stop and the window will cease to respond.

Similarly, if you have 2 threads and have created one form on each, and then joined one thread to the other, then one of the forms (the one started by the thread that is now sleeping) will become unresponsive because its message pump has stopped. As soon as the other thread finishes, the first thread will wake (thats what join does) and the message pump will start. Thing is, now, your other thread actually died, killing the message pump and youre possibly left with a dead window.

You'd be well advised to have the thread that created your first form, create all your forms, because it get s apain in the arse having lots of threads for lots of windows. Typically, the UI is a so-low cpu use affair that one thread can run all an apps windows so long as all intensive ops are done in the background.

Youre on 1.1 so you dont have the facility of the BackgroundWorker built into your .net but some nice person out there made it for you. GOogle for BackgroundWorker 1.1
 
Back
Top