Thread Sync Queue Problem

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • shipcreak@gmail.com

    #1

    Thread Sync Queue Problem

    I have an interesting problem with a sort of producer-consumer system
    for error logging. Consider the following code:

    <code>
    SyncLock _eventList.Sync Root

    Dim item As ExceptionLogEnt ry

    ' If there are items, get the top one
    If _eventList.Coun t > 0 Then

    ' Get the item from the queue
    item = CType(_eventLis t.Dequeue, _
    ExceptionLogEnt ry)

    ' If we got an item to log, log it
    If Not item Is Nothing Then

    WriteToLog(Buil dExceptionRepor t(item))

    End If

    End If

    End SyncLock
    </code>

    This method is running as a new thread, created thus:

    <code>
    _thread = New Thread(AddressO f StartWatching)
    _thread.Start()
    </code>

    FACTS:
    1) The _thread is System.Threadin g.Thread, the _eventList is
    System.Collecti ons.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.cou nt > 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.Threadin g

    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(AddressO f 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.Sync Root

    Dim item As ExceptionLogEnt ry

    ' If there are items, get the top one
    If _eventList.Coun t > 0 Then

    ' Get the item from the queue
    item = CType(_eventLis t.Dequeue, ExceptionLogEnt ry)

    ' If we got an item to log, log it
    If Not item Is Nothing Then

    WriteToLog(Buil dExceptionRepor t(item))

    End If

    End If

    End SyncLock


    ' Wait for 1 sec to allow other threads to take their turn
    Thread.CurrentT hread.Sleep(100 )

    End While

    End Sub

    Private Function BuildExceptionR eport( _
    ByVal ex As ExceptionLogEnt ry) As String

    Dim ret As New StringBuilder
    Dim e As ExceptionLogEnt ry = ex

    If Not e Is Nothing Then

    ret.AppendForma t("OS: {0}" & vbCrLf, ex.OSInfo)
    ret.AppendForma t("Processor usage: {0}" & vbCrLf, _
    ex.ProcessorUsa ge)
    ret.AppendForma t("Working Set: {0}" & vbCrLf, _
    ex.WorkingSet)
    ret.AppendForma t("Free Memory: {0}" & vbCrLf, _
    ex.FreeMemory)
    ret.AppendForma t("OS UserName: {0}" & vbCrLf, _
    ex.OSUserName)
    ret.AppendForma t("Machine Name: {0}" & vbCrLf, _
    ex.MachineName)
    'ret.AppendForm at("Total HDD: {0}" & vbCrLf, _
    ex.HDDTotal)
    'ret.AppendForm at("Free HDD: {0}" & vbCrLf, _
    ex.FreeHDD)
    ret.AppendForma t("Occurred At: {0}" & vbCrLf, _
    ex.Occurred)
    ret.Append("Exc eption details:" & vbCrLf)

    AppendException Details(ex.Caus ingException, ret)

    WriteToLog(ret. ToString)

    Else

    WriteToLog("No exception data provided")

    End If

    End Function

    Private Sub AppendException Details(ByVal ex As Exception, _
    ByVal report As StringBuilder)

    Dim e As Exception = e

    Do While Not e Is Nothing

    report.AppendFo rmat(" Message: {0}" & vbCrLf, _
    e.Message)
    report.AppendFo rmat(" Source: {0}" & vbCrLf, _
    e.Source)
    report.AppendFo rmat(" Method: {0}" & vbCrLf, _
    e.TargetSite.Na me)
    report.AppendFo rmat(" Help Link: {0}" & vbCrLf, _
    e.HelpLink)
    report.AppendFo rmat(" Stack Trace: {0}" & vbCrLf, _
    e.StackTrace)
    report.Append("------------------" & vbCrLf)

    e = e.InnerExceptio n

    Loop

    End Sub

    Protected MustOverride Sub WriteToLog(ByVa l item As String)
    Protected MustOverride Sub WriteToLog(ByVa l item As String, _
    ByVal type As EventLogEntryTy pe)

    End Class

  • Larry Lard

    #2
    Re: Thread Sync Queue Problem


    shipcreak@gmail .com wrote:[color=blue]
    > I have an interesting problem with a sort of producer-consumer system
    > for error logging. Consider the following code:
    >
    > <code>
    > SyncLock _eventList.Sync Root
    >
    > Dim item As ExceptionLogEnt ry
    >
    > ' If there are items, get the top one
    > If _eventList.Coun t > 0 Then
    >
    > ' Get the item from the queue
    > item = CType(_eventLis t.Dequeue, _
    > ExceptionLogEnt ry)
    >
    > ' If we got an item to log, log it
    > If Not item Is Nothing Then
    >
    > WriteToLog(Buil dExceptionRepor t(item))
    >
    > End If
    >
    > End If
    >
    > End SyncLock
    > </code>[/color]

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

    [snip][color=blue]
    > 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.cou nt > 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!?![/color]

    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("appl e")
    q.Enqueue("bana na")
    q.Enqueue(Nothi ng)
    q.Enqueue("pear ")

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

    Console.ReadLin e()
    End Sub

    --
    Larry Lard
    Replies to group please

    Comment

    • Barney

      #3
      Re: Thread Sync Queue Problem

      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 />

      Comment

      Working...