S
shipcreak
I have an interesting problem with a sort of producer-consumer system
for error logging. Consider the following code:
<code>
SyncLock _eventList.SyncRoot
Dim item As ExceptionLogEntry
' If there are items, get the top one
If _eventList.Count > 0 Then
' Get the item from the queue
item = CType(_eventList.Dequeue, _
ExceptionLogEntry)
' If we got an item to log, log it
If Not item Is Nothing Then
WriteToLog(BuildExceptionReport(item))
End If
End If
End SyncLock
</code>
This method is running as a new thread, created thus:
<code>
_thread = New Thread(AddressOf StartWatching)
_thread.Start()
</code>
FACTS:
1) The _thread is System.Threading.Thread, the _eventList is
System.Collections.Queue, both are member variables of the class.
2) The class this code appears in could have more than one instances
(hence using threading).
3) I'm using .NET 1.1.
4) The _eventList object is referenced by the producer class (not
listed here), where Enqueue is called inside a SyncLock block.
MY PROBLEM:
Thing is, it seems that "_eventList.count > 0" returns true, and still
is just before the dequeue call, but after the dequeue call it goes to
0, and "item" is NOTHING!!
I have no idea why this could be. Can anyone help!?!
Cheers,
<Shipcreak />
Full class follows:
Imports System.Text
Imports System.Threading
Public MustInherit Class LoggerBase
Private _name As String
Private _eventList As Queue
Private _thread As Thread
Private _stopRequested As Boolean
Public Sub New(ByVal pName As String)
_name = pName
End Sub
Public Sub AssignEventList(ByVal eventList As Queue)
If Not _eventList Is Nothing Then
SyncLock _eventList
_eventList = eventList
End SyncLock
Else
_eventList = eventList
End If
End Sub
Public Sub Start()
_stopRequested = False
_thread = New Thread(AddressOf StartWatching)
If Not _name Is Nothing AndAlso _name.Length > 0 Then
_thread.Name = _name
Else
_thread.Name = "Event Logging Thread"
End If
_thread.Start()
End Sub
Public Sub RequestStop()
_stopRequested = True
End Sub
Private Sub StartWatching()
While Not _stopRequested
' Lock the list
SyncLock _eventList.SyncRoot
Dim item As ExceptionLogEntry
' If there are items, get the top one
If _eventList.Count > 0 Then
' Get the item from the queue
item = CType(_eventList.Dequeue, ExceptionLogEntry)
' If we got an item to log, log it
If Not item Is Nothing Then
WriteToLog(BuildExceptionReport(item))
End If
End If
End SyncLock
' Wait for 1 sec to allow other threads to take their turn
Thread.CurrentThread.Sleep(100)
End While
End Sub
Private Function BuildExceptionReport( _
ByVal ex As ExceptionLogEntry) As String
Dim ret As New StringBuilder
Dim e As ExceptionLogEntry = ex
If Not e Is Nothing Then
ret.AppendFormat("OS: {0}" & vbCrLf, ex.OSInfo)
ret.AppendFormat("Processor usage: {0}" & vbCrLf, _
ex.ProcessorUsage)
ret.AppendFormat("Working Set: {0}" & vbCrLf, _
ex.WorkingSet)
ret.AppendFormat("Free Memory: {0}" & vbCrLf, _
ex.FreeMemory)
ret.AppendFormat("OS UserName: {0}" & vbCrLf, _
ex.OSUserName)
ret.AppendFormat("Machine Name: {0}" & vbCrLf, _
ex.MachineName)
'ret.AppendFormat("Total HDD: {0}" & vbCrLf, _
ex.HDDTotal)
'ret.AppendFormat("Free HDD: {0}" & vbCrLf, _
ex.FreeHDD)
ret.AppendFormat("Occurred At: {0}" & vbCrLf, _
ex.Occurred)
ret.Append("Exception details:" & vbCrLf)
AppendExceptionDetails(ex.CausingException, ret)
WriteToLog(ret.ToString)
Else
WriteToLog("No exception data provided")
End If
End Function
Private Sub AppendExceptionDetails(ByVal ex As Exception, _
ByVal report As StringBuilder)
Dim e As Exception = e
Do While Not e Is Nothing
report.AppendFormat(" Message: {0}" & vbCrLf, _
e.Message)
report.AppendFormat(" Source: {0}" & vbCrLf, _
e.Source)
report.AppendFormat(" Method: {0}" & vbCrLf, _
e.TargetSite.Name)
report.AppendFormat(" Help Link: {0}" & vbCrLf, _
e.HelpLink)
report.AppendFormat(" Stack Trace: {0}" & vbCrLf, _
e.StackTrace)
report.Append("------------------" & vbCrLf)
e = e.InnerException
Loop
End Sub
Protected MustOverride Sub WriteToLog(ByVal item As String)
Protected MustOverride Sub WriteToLog(ByVal item As String, _
ByVal type As EventLogEntryType)
End Class
for error logging. Consider the following code:
<code>
SyncLock _eventList.SyncRoot
Dim item As ExceptionLogEntry
' If there are items, get the top one
If _eventList.Count > 0 Then
' Get the item from the queue
item = CType(_eventList.Dequeue, _
ExceptionLogEntry)
' If we got an item to log, log it
If Not item Is Nothing Then
WriteToLog(BuildExceptionReport(item))
End If
End If
End SyncLock
</code>
This method is running as a new thread, created thus:
<code>
_thread = New Thread(AddressOf StartWatching)
_thread.Start()
</code>
FACTS:
1) The _thread is System.Threading.Thread, the _eventList is
System.Collections.Queue, both are member variables of the class.
2) The class this code appears in could have more than one instances
(hence using threading).
3) I'm using .NET 1.1.
4) The _eventList object is referenced by the producer class (not
listed here), where Enqueue is called inside a SyncLock block.
MY PROBLEM:
Thing is, it seems that "_eventList.count > 0" returns true, and still
is just before the dequeue call, but after the dequeue call it goes to
0, and "item" is NOTHING!!
I have no idea why this could be. Can anyone help!?!
Cheers,
<Shipcreak />
Full class follows:
Imports System.Text
Imports System.Threading
Public MustInherit Class LoggerBase
Private _name As String
Private _eventList As Queue
Private _thread As Thread
Private _stopRequested As Boolean
Public Sub New(ByVal pName As String)
_name = pName
End Sub
Public Sub AssignEventList(ByVal eventList As Queue)
If Not _eventList Is Nothing Then
SyncLock _eventList
_eventList = eventList
End SyncLock
Else
_eventList = eventList
End If
End Sub
Public Sub Start()
_stopRequested = False
_thread = New Thread(AddressOf StartWatching)
If Not _name Is Nothing AndAlso _name.Length > 0 Then
_thread.Name = _name
Else
_thread.Name = "Event Logging Thread"
End If
_thread.Start()
End Sub
Public Sub RequestStop()
_stopRequested = True
End Sub
Private Sub StartWatching()
While Not _stopRequested
' Lock the list
SyncLock _eventList.SyncRoot
Dim item As ExceptionLogEntry
' If there are items, get the top one
If _eventList.Count > 0 Then
' Get the item from the queue
item = CType(_eventList.Dequeue, ExceptionLogEntry)
' If we got an item to log, log it
If Not item Is Nothing Then
WriteToLog(BuildExceptionReport(item))
End If
End If
End SyncLock
' Wait for 1 sec to allow other threads to take their turn
Thread.CurrentThread.Sleep(100)
End While
End Sub
Private Function BuildExceptionReport( _
ByVal ex As ExceptionLogEntry) As String
Dim ret As New StringBuilder
Dim e As ExceptionLogEntry = ex
If Not e Is Nothing Then
ret.AppendFormat("OS: {0}" & vbCrLf, ex.OSInfo)
ret.AppendFormat("Processor usage: {0}" & vbCrLf, _
ex.ProcessorUsage)
ret.AppendFormat("Working Set: {0}" & vbCrLf, _
ex.WorkingSet)
ret.AppendFormat("Free Memory: {0}" & vbCrLf, _
ex.FreeMemory)
ret.AppendFormat("OS UserName: {0}" & vbCrLf, _
ex.OSUserName)
ret.AppendFormat("Machine Name: {0}" & vbCrLf, _
ex.MachineName)
'ret.AppendFormat("Total HDD: {0}" & vbCrLf, _
ex.HDDTotal)
'ret.AppendFormat("Free HDD: {0}" & vbCrLf, _
ex.FreeHDD)
ret.AppendFormat("Occurred At: {0}" & vbCrLf, _
ex.Occurred)
ret.Append("Exception details:" & vbCrLf)
AppendExceptionDetails(ex.CausingException, ret)
WriteToLog(ret.ToString)
Else
WriteToLog("No exception data provided")
End If
End Function
Private Sub AppendExceptionDetails(ByVal ex As Exception, _
ByVal report As StringBuilder)
Dim e As Exception = e
Do While Not e Is Nothing
report.AppendFormat(" Message: {0}" & vbCrLf, _
e.Message)
report.AppendFormat(" Source: {0}" & vbCrLf, _
e.Source)
report.AppendFormat(" Method: {0}" & vbCrLf, _
e.TargetSite.Name)
report.AppendFormat(" Help Link: {0}" & vbCrLf, _
e.HelpLink)
report.AppendFormat(" Stack Trace: {0}" & vbCrLf, _
e.StackTrace)
report.Append("------------------" & vbCrLf)
e = e.InnerException
Loop
End Sub
Protected MustOverride Sub WriteToLog(ByVal item As String)
Protected MustOverride Sub WriteToLog(ByVal item As String, _
ByVal type As EventLogEntryType)
End Class