In your situation, I don't understand why you want to use a ReaderWriterLock at all.  
You presumably have multiple threads adding new messages to the queue (writing), and 
only one (the queue flusher) that's reading.  Chad's description of when you might 
want an WRL is right on.

As Marek pointed out, you ought not "reset the queue" unless you hold a Write lock.

You should also be aware that the "stock" .NET ReaderWriterLock object implementation 
is very poor (in 1.x; hopefully it will be [already is?] better in 2.x).  (Sources:  
Jeffrey Richter, Jeff Prosise.)

Might I suggest an alternative design?  The class you expose should have some number 
of static "here's a new message" methods (perhaps all overloads with the same name, 
some that might do formatting, or take a boolean or "severity level" that won't 
actually store the message [and thus won't need to do the formatting] in some cases, 
etc).  Each of the static methods does something to turn its parameter(s) into a 
string and calls the version that accepts a string parameter.  (Of course, the callers 
using the static methods aren't forced to provide any synchronization.)

The class has a (private) Queue (or List or whatever) in which it stores messages.  
The static routine that accepts a string locks something (but not the private Queue 
into which it's storing) and adds the passed string to the Queue.  (The locking will 
serialize the calls from multiple threads.)

If the Queue isn't now full, it unlocks and exits; now other threads that were waiting 
for the lock will continue; one of them will get the lock.

If the Queue is full (however that's defined; for example, it could be deemed "full" 
if too much time has gone by since the last message was added), it stores a reference 
to the current Queue in a local variable, creates a new (empty) Queue (or List or 
whatever), replaces the class's reference to the Queue with a reference to the new 
Queue, and unlocks but does not yet exit.  (Now other threads will be freed up, and 
will add their messages in turn to the new Queue.)

The method then calls the thread pool's QueueUserWorkItem to run a method to push the 
contents of the no-longer-being-referenced-elsewhere Queue to wherever it goes, using 
code like what you've got now.  (When that method exits, the now-written Queue is no 
longer referenced and will get collected.)

The reason QUWI is used is so that if it takes longer to flush the queue than to fill 
the new queue (which had better not happen consistently or you'll have trouble!), the 
work to do the queue-flushing of the multiple separate full queues will be done in 
sequence.

At 03:11 PM 9/29/2004, Jekke Bladt wrote
>All--
>
>I'm having a problem with the ReadWriteLock object in .net and wondering
>if I'm misunderstanding the concept:
>
>The class I've written manages a log that stores messages in a queue and
>periodically flushes the queue to save the messages to a text file.
>
>In order to minimize blocking, I've written the class to copy the queue
>into an array, reset the queue, and release the reader lock. There is no
>place anywhere else that the queue is reinitialized or anything is
>dequeued.
>
>And yet, I am still having a problem where, during amsg = mQueue.ToArray
>is failing because the queue is empty. FileSave is never called with the
>queue empty.
>
>I suspect there's some conceptual error here, but I'll be damned if I
>can figure it out on my own. Can anyone help?
>
>TIA
>
>--Jekke
>[snip]


J. Merrill / Analytical Software Corp

===================================
This list is hosted by DevelopMentorŪ  http://www.develop.com
Some .NET courses you may be interested in:

Essential .NET: building applications and components with CSharp
August 30 - September 3, in Los Angeles
http://www.develop.com/courses/edotnet

View archives and manage your subscription(s) at http://discuss.develop.com

Reply via email to