Multithreading...


M

Mobileboy36

Hi Group,

I built a TCP server handling multiple clients simultanously; everything is
working fine, except updating a listbox lstclients based on the funtion
_MyTcpServer.GetConnectedClients. Cross thread problems are known for me but
I don't understand the way
to handle them. Last year I found SafeUIInvoker on
http://weblogs.asp.net/rosherove/archive/2005/05/23/408511.aspx.
(you can find it below). Do you think this SafeUIInvoker is a possible way
to handle with cross thread exceptions?
Or can I simply set me.CheckForIllegalCrossThreadCalls to False?
Or is there another way to make the _MyTcpServer.GetConnectedClients thread
safe?


' A WINDOWS FORM
' --------------

Private Sub OnClientConnected(ByVal Sender As Object, ByVal e As
MyTcpServerAndClientEventArgs) Handles _MyTcpServer.OnClientConnected
FillListBox()
End Sub

Private Sub OnClientDisConnected(ByVal Sender As Object, ByVal e As
MyTcpServerAndClientEventArgs) Handles _MyTcpServer.OnClientDisConnected
FillListBox()
End Sub

Private Sub OnClientInfoListUpdated() Handles
_MyTcpServer.OnClientInfoListUpdated
FillListBox()
End Sub


Private Sub FillListBox()
' used to refill the listbox lstclients with clientnames when a new client
Connects, Disconnects or

If SafeUIInvoker.Invoke(Me) Then
Exit Sub
End If

lstClients.Items.Clear()
lstClients.ValueMember = "ci"
lstClients.DisplayMember = "Id"

For Each Ci As ClientInfo In _MyTcpServer.GetConnectedClients
lstClients.Items.Add(Ci)
Next

End Sub


'







' The class SafeUIInvoker
' -----------------------


' THE SafeUIInvoker Class found last year on
http://weblogs.asp.net/rosherove/archive/2005/05/23/408511.aspx
' Examples at the end of this file
Imports System.ComponentModel
Imports System.Diagnostics
Imports System.Reflection


''' <summary>
''' Use this class if you have to update user controls in events generated
''' from within another thread
''' Example usage:
''' If SafeUIInvoker.Invoke(Me, Sender, e) Then
''' Exit Sub
''' End If
''' </summary>
''' <remarks></remarks>
Public Class SafeUIInvoker
Private Shared ReadOnly _instance As New SafeUIInvoker()

Private Sub New()
End Sub

Private Shared _ownTypeName As String = GetType(SafeUIInvoker).Name

Public Shared Function getOriginalCallingMethod() As MemberInfo
Dim trace As New StackTrace()
For i As Integer = 1 To trace.FrameCount - 1
Dim pastFrame As StackFrame = trace.GetFrame(i)
Dim pastMethod As MemberInfo = pastFrame.GetMethod()
If pastMethod.DeclaringType.Name <> _ownTypeName Then
Return pastMethod
End If
Next

Return Nothing
End Function


Private Function invokeSafely(ByVal thisTarget As Object, ByRef
returnValue As Object, ByVal ParamArray realArgs As Object()) As Boolean
returnValue = Nothing
'Any Form inherits from Control which implements this interfaces
'this interfaces allows us to determine whethere we are on the UI
thread or not
'and to invoke the method on the UI thread usine Control.Invoke() if
needed
Dim invokeableObject As ISynchronizeInvoke = TryCast(thisTarget,
ISynchronizeInvoke)
If invokeableObject Is Nothing OrElse (Not
invokeableObject.InvokeRequired) Then
Return False
End If

Dim callerMethodInfo As MethodInfo =
TryCast(getOriginalCallingMethod(), MethodInfo)
If callerMethodInfo Is Nothing Then
Return False
End If


Dim delgateToLocalMethodThatTakesAllArguments As New
UISafeInvocationDelegate(AddressOf _instance.UIThreadInvocation)
Dim passDownArgsToRealMethod As Object() = New Object()
{callerMethodInfo, invokeableObject, realArgs}

returnValue =
invokeableObject.Invoke(delgateToLocalMethodThatTakesAllArguments,
passDownArgsToRealMethod)

Return True
End Function


Private Delegate Function UISafeInvocationDelegate(ByVal method As
MethodInfo, ByVal target As Object, ByVal args As Object()) As Object
'private delegate object UISafeInvocationDelegate(MethodInfo method,
object target, params object[] args);

Private Function UIThreadInvocation(ByVal method As MethodInfo, ByVal
target As Object, ByVal ParamArray args As Object()) As Object
'if we're here we're already inside the UI thread
'as we've been invoked from a Control.Invoke method
'so we simply forward the call to the *real* method on the target
object
Return method.Invoke(target, args)
End Function



#Region "public interface"

Public Shared Function Invoke(ByVal target As Object, ByVal ParamArray
args As Object()) As Boolean
Dim result As Object
Return _instance.invokeSafely(target, result, args)
End Function


Public Shared Function InvokeAndReturn(ByVal thisInstanceTarget As
Object, ByVal ParamArray methodParams As Object()) As Object
Dim result As Object
_instance.invokeSafely(thisInstanceTarget, result, methodParams)
Return result
End Function

#End Region
End Class


''EXAMPLE: this shows how to work with the TeamAgile SafeUIInvoker class
'Public Class MyForm
' Inherits Form

' Public Sub ThreadSafeEmptyMethod()
' If SafeUIInvoker.Invoke(Me) Then
' Return
' End If

' 'do whatever GUI things you want here!
' End Sub

' Public Sub ThreadSafeMethodWithParams(ByVal i As Integer, ByVal str As
String)
' If SafeUIInvoker.Invoke(Me, i, str) Then
' Return
' End If

' 'do whatever GUI things you want here!
' End Sub

' Public Function ThreadSafeMethodWithParamsAndReturnValue(ByVal i As
Integer, ByVal str As String) As Integer
' If InvokeRequired Then
' Return SafeUIInvoker.InvokeAndReturn(Me, i, str)
' End If


' 'do whatever GUI things you want here!
' TextBox1.Text = "whatever"
' Return 1
' End Function
'End Class
 
Ad

Advertisements

C

Cor Ligthert[MVP]

Hi,

What is your goal, to use this code or to fill the listbox?

Cor

Mobileboy36 said:
Hi Group,

I built a TCP server handling multiple clients simultanously; everything
is working fine, except updating a listbox lstclients based on the funtion
_MyTcpServer.GetConnectedClients. Cross thread problems are known for me
but I don't understand the way
to handle them. Last year I found SafeUIInvoker on
http://weblogs.asp.net/rosherove/archive/2005/05/23/408511.aspx.
(you can find it below). Do you think this SafeUIInvoker is a possible way
to handle with cross thread exceptions?
Or can I simply set me.CheckForIllegalCrossThreadCalls to False?
Or is there another way to make the _MyTcpServer.GetConnectedClients
thread safe?


' A WINDOWS FORM
' --------------

Private Sub OnClientConnected(ByVal Sender As Object, ByVal e As
MyTcpServerAndClientEventArgs) Handles _MyTcpServer.OnClientConnected
FillListBox()
End Sub

Private Sub OnClientDisConnected(ByVal Sender As Object, ByVal e As
MyTcpServerAndClientEventArgs) Handles _MyTcpServer.OnClientDisConnected
FillListBox()
End Sub

Private Sub OnClientInfoListUpdated() Handles
_MyTcpServer.OnClientInfoListUpdated
FillListBox()
End Sub


Private Sub FillListBox()
' used to refill the listbox lstclients with clientnames when a new client
Connects, Disconnects or

If SafeUIInvoker.Invoke(Me) Then
Exit Sub
End If

lstClients.Items.Clear()
lstClients.ValueMember = "ci"
lstClients.DisplayMember = "Id"

For Each Ci As ClientInfo In _MyTcpServer.GetConnectedClients
lstClients.Items.Add(Ci)
Next

End Sub


'







' The class SafeUIInvoker
' -----------------------


' THE SafeUIInvoker Class found last year on
http://weblogs.asp.net/rosherove/archive/2005/05/23/408511.aspx
' Examples at the end of this file
Imports System.ComponentModel
Imports System.Diagnostics
Imports System.Reflection


''' <summary>
''' Use this class if you have to update user controls in events generated
''' from within another thread
''' Example usage:
''' If SafeUIInvoker.Invoke(Me, Sender, e) Then
''' Exit Sub
''' End If
''' </summary>
''' <remarks></remarks>
Public Class SafeUIInvoker
Private Shared ReadOnly _instance As New SafeUIInvoker()

Private Sub New()
End Sub

Private Shared _ownTypeName As String = GetType(SafeUIInvoker).Name

Public Shared Function getOriginalCallingMethod() As MemberInfo
Dim trace As New StackTrace()
For i As Integer = 1 To trace.FrameCount - 1
Dim pastFrame As StackFrame = trace.GetFrame(i)
Dim pastMethod As MemberInfo = pastFrame.GetMethod()
If pastMethod.DeclaringType.Name <> _ownTypeName Then
Return pastMethod
End If
Next

Return Nothing
End Function


Private Function invokeSafely(ByVal thisTarget As Object, ByRef
returnValue As Object, ByVal ParamArray realArgs As Object()) As Boolean
returnValue = Nothing
'Any Form inherits from Control which implements this interfaces
'this interfaces allows us to determine whethere we are on the UI
thread or not
'and to invoke the method on the UI thread usine Control.Invoke()
if needed
Dim invokeableObject As ISynchronizeInvoke = TryCast(thisTarget,
ISynchronizeInvoke)
If invokeableObject Is Nothing OrElse (Not
invokeableObject.InvokeRequired) Then
Return False
End If

Dim callerMethodInfo As MethodInfo =
TryCast(getOriginalCallingMethod(), MethodInfo)
If callerMethodInfo Is Nothing Then
Return False
End If


Dim delgateToLocalMethodThatTakesAllArguments As New
UISafeInvocationDelegate(AddressOf _instance.UIThreadInvocation)
Dim passDownArgsToRealMethod As Object() = New Object()
{callerMethodInfo, invokeableObject, realArgs}

returnValue =
invokeableObject.Invoke(delgateToLocalMethodThatTakesAllArguments,
passDownArgsToRealMethod)

Return True
End Function


Private Delegate Function UISafeInvocationDelegate(ByVal method As
MethodInfo, ByVal target As Object, ByVal args As Object()) As Object
'private delegate object UISafeInvocationDelegate(MethodInfo method,
object target, params object[] args);

Private Function UIThreadInvocation(ByVal method As MethodInfo, ByVal
target As Object, ByVal ParamArray args As Object()) As Object
'if we're here we're already inside the UI thread
'as we've been invoked from a Control.Invoke method
'so we simply forward the call to the *real* method on the target
object
Return method.Invoke(target, args)
End Function



#Region "public interface"

Public Shared Function Invoke(ByVal target As Object, ByVal ParamArray
args As Object()) As Boolean
Dim result As Object
Return _instance.invokeSafely(target, result, args)
End Function


Public Shared Function InvokeAndReturn(ByVal thisInstanceTarget As
Object, ByVal ParamArray methodParams As Object()) As Object
Dim result As Object
_instance.invokeSafely(thisInstanceTarget, result, methodParams)
Return result
End Function

#End Region
End Class


''EXAMPLE: this shows how to work with the TeamAgile SafeUIInvoker class
'Public Class MyForm
' Inherits Form

' Public Sub ThreadSafeEmptyMethod()
' If SafeUIInvoker.Invoke(Me) Then
' Return
' End If

' 'do whatever GUI things you want here!
' End Sub

' Public Sub ThreadSafeMethodWithParams(ByVal i As Integer, ByVal str
As String)
' If SafeUIInvoker.Invoke(Me, i, str) Then
' Return
' End If

' 'do whatever GUI things you want here!
' End Sub

' Public Function ThreadSafeMethodWithParamsAndReturnValue(ByVal i As
Integer, ByVal str As String) As Integer
' If InvokeRequired Then
' Return SafeUIInvoker.InvokeAndReturn(Me, i, str)
' End If


' 'do whatever GUI things you want here!
' TextBox1.Text = "whatever"
' Return 1
' End Function
'End Class
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top