Thread Sync Queue Problem

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
 
L

Larry Lard

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>

In my not-particularly-expert opinion, this looks OK.

[snip]
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!?!

I think you're going to have to have a look at the enqueueing code, and
if you can't find the problem, post some of it. The key point which you
may need reminding of (from the docs, my emphasis):


Queue.Enqueue Method

Adds an object to the end of the Queue.

Public Overridable Sub Enqueue( _
ByVal obj As Object _
)

Parameters
obj
The object to add to the Queue. ****The value can be a null reference
(Nothing in Visual Basic). ****



My example code:

Sub Main()
Dim q As New Queue

q.Enqueue("apple")
q.Enqueue("banana")
q.Enqueue(Nothing)
q.Enqueue("pear")

Dim o As Object
Do While q.Count > 0
o = q.Dequeue
' everything implements ToString, right?
Console.WriteLine(o.ToString)
' OOPS
Loop

Console.ReadLine()
End Sub
 
B

Barney

Yeah, you're right. I worked out what it was yesterday afternoon
eventually.

I was adding the result of a call to a factory class method to the
queue, but the factory was returning Nothing.

Put null in, get null out. Simple.

Thanks for the reply, one's never guaranteed one in here, so many
people with so many problems an' all that. :)

<Shipcreak />
 

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