Hi all,
I'm trying to program a multithreaded application - it currently
works, but I have two problems. I'm relatively new to VB.NET (C and
VB6 are my things) so I'm a bit lost here. The code is based on the
countdown / controlinvoker quickstart at GotDotNet.com.
The problems are:
(1) There's a memory leak somewhere. I don't know where, but it's
probably something stupid I've done when I added a second thread.
(2) How do I set it up to exit gracefully (i.e. where in the
application should I set threadsRunning = FALSE); at the moment even
when in debug mode it crashes when stopping - I assume because I
haven't sewn things up properly.
The basics of the thread architecture are below. I've added a second
thread to the quickstart code, and I've added a second ControlInvoker
instance. With regard to the two threads, one updates the screen and
the other communicates with a data comms interface, and passes some of
this data to the serial port. The communications routine should take
priority over the screen updating.
Can anyone cast an expert eye over it and tell me where I'm being
thick?
Thanks
Andy
===========================
' main application class:
Public Class Form1
Inherits System.Windows.Forms.Form
Private thrComms As Thread
Private thrDisplayUpdate As Thread
Private threadsRunning As Boolean
Private controlInvoker As controlInvoker
Private controlInvoker2 As controlInvoker
' ...
Public Sub New()
MyBase.New()
Try
'This call is required by the Windows Form Designer.
InitializeComponent()
Catch ex As Exception
Stop
End Try
' InitialiseSerialPort()
'Me.CreateGraphics()
'Add any initialization after the InitializeComponent() call
Me.thrComms = New Thread(New ThreadStart(AddressOf
Me.Thread_232))
Me.thrDisplayUpdate = New Thread(New ThreadStart(AddressOf
Me.Thread_DisplayUpdate))
controlInvoker = New ControlInvoker(Me)
controlInvoker2 = New ControlInvoker(Me)
Me.thrComms.Priority = ThreadPriority.AboveNormal
Me.thrDisplayUpdate.Priority = ThreadPriority.Normal
Me.thrComms.Start()
Me.thrDisplayUpdate.Start()
Me.threadsRunning = True
End Sub
'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As
Boolean)
MyBase.Dispose(disposing)
End Sub
' ....
Public Sub Thread_232()
' Data comms worker thread
Dim rxmsg_counter As Integer
Dim messages As sPCCanMsg
Dim temp_sec_value As Integer
controlInvoker = New ControlInvoker(Me)
'worker thread
Do
msg_list_size = 50
controlInvoker.Invoke(New MethodCallInvoker(AddressOf
interface_read_Wrapper))
' get 50 messages
If (returned_status = HTX_SUCCESS) Then
' do processing
End If
'...
If cycle_count > 50 Then
' reset interface
'Thread.Sleep(1)
controlInvoker.Invoke(New
MethodCallInvoker(AddressOf interface_stop_Wrapper))
'Thread.Sleep(1)
controlInvoker.Invoke(New
MethodCallInvoker(AddressOf interface_start_Wrapper))
cycle_count = 0
End If
Loop While Me.threadsRunning
End Sub
Public Sub Thread_display()
controlInvoker2 = New ControlInvoker(Me)
Do
controlInvoker2.Invoke(New MethodCallInvoker(AddressOf
update_display_wrapper))
Loop While Me.threadRunning
End Sub
Private Sub update_display_wrapper(ByVal arguments() As Object)
'----- Start the Display task
' Gets data from Global Variables, scales data and updates the screen.
' ......do lots of screen updating....
End Sub
Private Sub interface_start_wrapper(ByVal arguments() As Object)
canstatus2 = InterfaceStart(1) ' DLL call to start the data comms
interface
End Sub
Private Sub interface_stop_wrapper(ByVal arguments() As Object)
canstatus2 = InterfaceStop(1)' DLL call to stop the data comms
interface
End Sub
Private Sub interface_read_wrapper(ByVal arguments() As Object)
canstatus2 = InterfaceReadEx(1, msg_list(0), 5, 50)' DLL call to
read 50 messages from data comms interface
End Sub
End Class
=====================================
'''' CONTROLINVOKER CLASS ''''
Imports System
Imports System.Collections
Imports System.Windows.Forms
Public Delegate Sub MethodCallInvoker(ByVal o() As Object)
' Control.Invoke allows a method to be invoked on the same thread as
the one
' the control was created on. Unlike in the full .NET Framework, the
..NET
' Compact Framework does not support the Control.Invoke overload for
passing an
' array of objects to pass as arguments. This ControlInvoker class
overcomes
' this limitation.
Public Class ControlInvoker
Private Class MethodCall
Public invoker As MethodCallInvoker
Public arguments() As Object
Public Sub New(ByVal invoker As MethodCallInvoker, ByVal
arguments() As Object)
Me.invoker = invoker
Me.arguments = arguments
End Sub 'New
End Class 'MethodCall
Private control As Control
Private argumentInvokeList As New Queue
' The constructor typically takes a form
Public Sub New(ByVal control As Control)
Me.control = control
End Sub 'New
' The delegate wrapping the method and its arguments
' to be called on the same thread as the control.
Public Sub Invoke(ByVal invoker As MethodCallInvoker, ByVal
ParamArray arguments() As Object)
Me.argumentInvokeList.Enqueue(New MethodCall(invoker,
arguments))
control.Invoke(New EventHandler(AddressOf ControlInvoke))
End Sub 'Invoke
Private Sub ControlInvoke(ByVal sender As Object, ByVal e As
EventArgs)
Dim methodCall As MethodCall =
CType(argumentInvokeList.Dequeue(), MethodCall)
Try
methodCall.invoker(methodCall.arguments)
Catch ex As Exception
Debug.Assert(False)
End Try
End Sub 'ControlInvoke
End Class 'ControlInvoker