I am having problem with thread. I have a Session class with public string
variable (called Message) that I set from my Main program. In the session
class it checks for the value of Message while inside it's "read loop"
waiting for data from the client. I find that many times while inside the
"read loop" it missed many of the value that was assigned to the public
Message variable.
For example, the main program send number 1 thru 100, but the Session class
is missing number 2, 15, 23, etc. In my sample program below, file
LogFrom.txt will have more numbers than file LogTo.txt.
Somebody told me that I am using a timer to set the Message member of the
client session object, but I never check to make sure that data is actually
sent to the client before I change it again. It's possible that the timer
could fire again in the main thread, changing the "message" before the
thread that's handling the client session has had the chance to send the
previous value (the session thread may be asleep, it may be reading data,
etc.). He suggested to use synchronization objects and some mechanism to
communicate state changes in different threads. For example, check to see if
the Message member has been cleared before changing its value in the timer
event of the main thread, that way you know it has been written by the
session thread. For example, in my codes below in the sub Test, do the
following
Do While Client(lIndex). Session.Message <> ""
Loop
Client(nIndex). Session.Message = m_cnt
But, if I do this, it will slow down sending and receiving the messsage to
the thread. Is there any other way to fix this problem so that the client
thread gets all the Messages that the Main program send ?
To try my sample code, create a command button and name it TestButton. To
run the program cllick on the Test button. It will create a file
c:\LogFrom.txt and c:\LogTo.txt, and you will see that LogFrom.txt will have
more numbers than LogTo.txt, and they are suppose to have the same data.
Thank you very much for your help.
'************** **Main program******** *************** **
Imports System.Threadin g
Imports System.IO
Private Structure SessionInfo
Dim Session As SessionClass
Dim Thread As Threading.Threa d
End Structure
Private Client(0) As SessionInfo
Private LastClient As Integer
Private m_cnt As Long
Public Function RegisterClient( ByRef Session As SessionClass, ByRef Thread
As Threading.Threa d) As Boolean
Dim nIndex As Integer
Dim nMaxClients As Integer
RegisterClient = False
nMaxClients = Val(MaxClients. Text)
Monitor.Enter(C lient)
For nIndex = 0 To LastClient - 1
If Client(nIndex). Session Is Nothing Then
Client(nIndex). Session = Session
Client(nIndex). Thread = Thread
RegisterClient = True
Monitor.Exit(Cl ient)
Exit Function
End If
Next
ReDim Preserve Client(LastClie nt)
Client(LastClie nt).Session = Session
Client(LastClie nt).Thread = Thread
LastClient = LastClient + 1
RegisterClient = True
Monitor.Exit(Cl ient)
End Function
Public Function UnregisterClien t(ByRef Session As SessionClass) As Boolean
Dim nIndex As Integer
UnregisterClien t = False
Monitor.Enter(C lient)
For nIndex = 0 To LastClient - 1
If Client(nIndex). Session Is Session Then
Client(nIndex). Session = Nothing
Client(nIndex). Thread = Nothing
UnregisterClien t = True
Exit For
End If
Next
Monitor.Exit(Cl ient)
End Function
Private Sub TestButton_Clic k(ByVal sender As Object, ByVal e As
System.EventArg s) Handles TestButton.Clic k
Dim oSession As SessionClass
Dim oThread As Threading.Threa d
Static nSession As Long
nSession = nSession + 1
oSession = New SessionClass
oSession.Server = Me
oThread = New Threading.Threa d(AddressOf oSession.Thread Main)
oThread.Apartme ntState = ApartmentState. STA
oThread.Name = "Session" & CLng(nSession)
oThread.Start()
Timer1.Enabled = True
End Sub
Sub Test()
Dim sw As StreamWriter
Dim nIndex As Integer
Monitor.Enter(C lient)
For nIndex = 0 To LastClient - 1
If Not Client(nIndex). Session Is Nothing Then
Client(nIndex). Session.Message = m_cnt
sw = File.AppendText ("c:\logFrom.tx t")
sw.WriteLine(m_ cnt)
sw.Close()
End If
Next
Monitor.Exit(Cl ient)
End Sub
Private Sub Timer1_Tick(ByV al sender As System.Object, ByVal e As
System.EventArg s) Handles Timer1.Tick
m_cnt = m_cnt + 1
Test()
End Sub
'*************S ession.vb****** **************
Imports System.Threadin g
Imports System.IO
Public Class SessionClass
Public Server As ServerForm
Public Message As String
Private Terminated As Boolean
Public Sub ThreadMain()
Dim nThreadId As Integer
Dim strThreadName As String
Dim strBuffer As String
Dim nResult As Integer
Dim sw As StreamWriter
nThreadId = Thread.GetDomai n().GetCurrentT hreadId()
strThreadName = "Thread " & Hex(nThreadId) & " (" &
Thread.CurrentT hread.Name & ")"
If Server.Register Client(Me, Thread.CurrentT hread()) = False Then
Exit Sub
End If
Do While Not Terminated
If Len(Me.Message) > 0 Then
sw = File.AppendText ("c:\logTo.txt" )
sw.WriteLine(Me .Message)
sw.Close()
Me.Message = ""
End If
Loop
Server.Unregist erClient(Me)
Exit Sub
End Sub
Public Sub Terminate()
Terminated = True
End Sub
variable (called Message) that I set from my Main program. In the session
class it checks for the value of Message while inside it's "read loop"
waiting for data from the client. I find that many times while inside the
"read loop" it missed many of the value that was assigned to the public
Message variable.
For example, the main program send number 1 thru 100, but the Session class
is missing number 2, 15, 23, etc. In my sample program below, file
LogFrom.txt will have more numbers than file LogTo.txt.
Somebody told me that I am using a timer to set the Message member of the
client session object, but I never check to make sure that data is actually
sent to the client before I change it again. It's possible that the timer
could fire again in the main thread, changing the "message" before the
thread that's handling the client session has had the chance to send the
previous value (the session thread may be asleep, it may be reading data,
etc.). He suggested to use synchronization objects and some mechanism to
communicate state changes in different threads. For example, check to see if
the Message member has been cleared before changing its value in the timer
event of the main thread, that way you know it has been written by the
session thread. For example, in my codes below in the sub Test, do the
following
Do While Client(lIndex). Session.Message <> ""
Loop
Client(nIndex). Session.Message = m_cnt
But, if I do this, it will slow down sending and receiving the messsage to
the thread. Is there any other way to fix this problem so that the client
thread gets all the Messages that the Main program send ?
To try my sample code, create a command button and name it TestButton. To
run the program cllick on the Test button. It will create a file
c:\LogFrom.txt and c:\LogTo.txt, and you will see that LogFrom.txt will have
more numbers than LogTo.txt, and they are suppose to have the same data.
Thank you very much for your help.
'************** **Main program******** *************** **
Imports System.Threadin g
Imports System.IO
Private Structure SessionInfo
Dim Session As SessionClass
Dim Thread As Threading.Threa d
End Structure
Private Client(0) As SessionInfo
Private LastClient As Integer
Private m_cnt As Long
Public Function RegisterClient( ByRef Session As SessionClass, ByRef Thread
As Threading.Threa d) As Boolean
Dim nIndex As Integer
Dim nMaxClients As Integer
RegisterClient = False
nMaxClients = Val(MaxClients. Text)
Monitor.Enter(C lient)
For nIndex = 0 To LastClient - 1
If Client(nIndex). Session Is Nothing Then
Client(nIndex). Session = Session
Client(nIndex). Thread = Thread
RegisterClient = True
Monitor.Exit(Cl ient)
Exit Function
End If
Next
ReDim Preserve Client(LastClie nt)
Client(LastClie nt).Session = Session
Client(LastClie nt).Thread = Thread
LastClient = LastClient + 1
RegisterClient = True
Monitor.Exit(Cl ient)
End Function
Public Function UnregisterClien t(ByRef Session As SessionClass) As Boolean
Dim nIndex As Integer
UnregisterClien t = False
Monitor.Enter(C lient)
For nIndex = 0 To LastClient - 1
If Client(nIndex). Session Is Session Then
Client(nIndex). Session = Nothing
Client(nIndex). Thread = Nothing
UnregisterClien t = True
Exit For
End If
Next
Monitor.Exit(Cl ient)
End Function
Private Sub TestButton_Clic k(ByVal sender As Object, ByVal e As
System.EventArg s) Handles TestButton.Clic k
Dim oSession As SessionClass
Dim oThread As Threading.Threa d
Static nSession As Long
nSession = nSession + 1
oSession = New SessionClass
oSession.Server = Me
oThread = New Threading.Threa d(AddressOf oSession.Thread Main)
oThread.Apartme ntState = ApartmentState. STA
oThread.Name = "Session" & CLng(nSession)
oThread.Start()
Timer1.Enabled = True
End Sub
Sub Test()
Dim sw As StreamWriter
Dim nIndex As Integer
Monitor.Enter(C lient)
For nIndex = 0 To LastClient - 1
If Not Client(nIndex). Session Is Nothing Then
Client(nIndex). Session.Message = m_cnt
sw = File.AppendText ("c:\logFrom.tx t")
sw.WriteLine(m_ cnt)
sw.Close()
End If
Next
Monitor.Exit(Cl ient)
End Sub
Private Sub Timer1_Tick(ByV al sender As System.Object, ByVal e As
System.EventArg s) Handles Timer1.Tick
m_cnt = m_cnt + 1
Test()
End Sub
'*************S ession.vb****** **************
Imports System.Threadin g
Imports System.IO
Public Class SessionClass
Public Server As ServerForm
Public Message As String
Private Terminated As Boolean
Public Sub ThreadMain()
Dim nThreadId As Integer
Dim strThreadName As String
Dim strBuffer As String
Dim nResult As Integer
Dim sw As StreamWriter
nThreadId = Thread.GetDomai n().GetCurrentT hreadId()
strThreadName = "Thread " & Hex(nThreadId) & " (" &
Thread.CurrentT hread.Name & ")"
If Server.Register Client(Me, Thread.CurrentT hread()) = False Then
Exit Sub
End If
Do While Not Terminated
If Len(Me.Message) > 0 Then
sw = File.AppendText ("c:\logTo.txt" )
sw.WriteLine(Me .Message)
sw.Close()
Me.Message = ""
End If
Loop
Server.Unregist erClient(Me)
Exit Sub
End Sub
Public Sub Terminate()
Terminated = True
End Sub