I had the same problem about a year ago. The solution I came up with is the
abstract class below. Yes, this is a C# group and the class is in VB, but
the concept is the same. It uses a Linked List instead of a queue because
the linked list actually provides both better performance and memory usage
when the inputs are coming faster than they can be processed.
Derive a class from this and provide the "private StatusFlag ProcessValue(T
value)". Note the protected bool isBackground property that default to
"false" so all the items added to the queue will be processed before the
thread ends.
Mike.
======================
Option Explicit On
Option Strict On
Option Compare Text
Imports System.Collections.ObjectModel
Imports System.Threading
Public MustInherit Class ProcessingQueue(Of T)
<Flags()_
Public Enum StatusFlag
GetNextValue = 0
ExitThread = 1
RequeueValue = 2
End Enum
Private Queue As New QuickQueue(Of T)
Public MustOverride Function ProcessValue(ByVal value As T) As StatusFlag
' Thread control
Protected isBackground As Boolean = False
Protected Name As String = ""
Private th As New Thread(AddressOf ThreadProc)
' Statistical information
Private mTotalAdded As Integer = 0
Private syncTotalAdded As New SynchronizationContext
' NOTHING is legal - it simply forces the workerthreadproc to be started
Public Sub Add()
add(Nothing)
End Sub
Public Sub Add(ByVal value As T)
If value IsNot Nothing Then Queue.Enqueue(value)
SyncLock syncTotalAdded
If value IsNot Nothing Then mTotalAdded += 1
If Count = 0 Then Exit Sub
If th.IsAlive Then Exit Sub
th = New Thread(AddressOf ThreadProc)
th.IsBackground = isBackground
If Name <"" Then th.Name = Name
th.Start()
End SyncLock
End Sub
Protected Sub New()
End Sub
Public Sub Join()
On Error Resume Next
Do While Me.Count 0
th.Join()
Loop
End Sub
Private Sub ThreadProc()
Dim value As T = Queue.Dequeue()
Do While value IsNot Nothing
Try
Dim result As StatusFlag = ProcessValue(value)
If (result And ProcessingQueue(Of T).StatusFlag.RequeueValue) =
StatusFlag.RequeueValue Then Queue.Enqueue(value)
If (result And ProcessingQueue(Of T).StatusFlag.ExitThread) =
StatusFlag.ExitThread Then Exit Do
value = Queue.Dequeue()
Catch ex As Exception
WriteLog(ex)
End Try
Loop
End Sub
Public ReadOnly Property Count() As Integer
Get
Return Queue.Count
End Get
End Property
Public ReadOnly Property TotalAdded() As Integer
Get
SyncLock syncTotalAdded
Return mTotalAdded
End SyncLock
End Get
End Property
Private Class QuickQueue(Of QuickQueue_Element)
Private Queue As New LinkedList(Of QuickQueue_Element)
Private so As New SynchronizationContext
Public Sub Enqueue(ByVal value As QuickQueue_Element)
SyncLock so
Queue.AddLast(value)
End SyncLock
End Sub
Public Function Dequeue() As QuickQueue_Element
Dim r As QuickQueue_Element = Nothing
SyncLock so
Try
r = CType(Queue.First().Value, QuickQueue_Element)
Queue.RemoveFirst()
Catch
End Try
End SyncLock
Return r
End Function
Public ReadOnly Property Count() As Integer
Get
SyncLock so
Return Queue.Count
End SyncLock
End Get
End Property
End Class
End Class
======================
"P.J.M. Beker" <pj******@orange.nlwrote in message
news:48***********************@news.wanadoo.nl...
Hi there,
I'm currently writing a program in which I use the FileMonitor to monitor
a folder in which I store downloaded images. I know that I can't add much
coding in the filemonitor's event in risk of losing some new entries, so
I've deceided to create an update thread. This thread is created when the
program's start and should (for various reason) run not in sync with the
Filemonitor.
The Filemonitor event creates an entry in a database table (lets call it
TEMP) in which it stores the location and name of a new image. The update
thread scans this table and if it finds any entries, is does a serie of
operations (hash calculation, check for multiple entries etc). The thread
then creates a new entry in table [QUEUE] in which it stores the image
title, location, hashvalue etc.Then it gets the next entry in table TEMP.
If there aren't any records left, it goes to sleep. When waking up it
scans table TEMP again.
Here is my problem. When terminating my program, the update thread should
stop, but only after it finishes processing the current image it's working
on. It should not create any corrupted/broken records. How can I prevent
this from happening?
// Main Program
private void FileMonitor_Created(Object sender, FileSystemEventArgs e)
{
// Creates a new record in table TEMP
CreateNewTempEntry(e.FullPath);
}
// Update Thread
private void ScanTempTable()
{
OleDbCommand myCmd = new OleDBCommand("SELECT * FROM TEMP");
myCmd.Connection = ...;
OleDbDataReader myReader = myCmd.ExecuteReader();
string myFile = "", myHash = "";
bool bFound = false;
while(myReader.Read())
{
myFile = myReader.GetString(0);
myHash = CalcHash(myFile);
bFound = Scan4MultipleImages(myHash)
-----------------------------------------------------------
// Thread isn't allow to stop here
WriteNewImageRecord(myFile, myHash, bFound);
// Thread can stop now
------------------------------------------------------------
}
// Sleep for a while
}
thnx in advance
Peter