Also, note that the ReaderWriterLock is only appropriate for use in
scenarios where it really is safe to have multiple concurrent readers.
This will often not be the case.

If the Queue is a System.Collections.Queue, the docs have this to say:

"Instance members are not guaranteed to be thread-safe."

Note that it doesn't say anything about concurrent reads being OK.  And
since it doesn't say that you shouldn't assume that they are.  In
scenarios where concurrent reads *are* OK, the docs are explicit about
this. For example, the docs for System.Data.DataTable say this:

"This type is safe for multithreaded read operations. You must
synchronize any write operations."

For classes with that promise, then a ReaderWriterLock might be
appropriate. (Although be careful you understand that constitutes a
'write'. For example, bizarrely enough DataTable.Select is considered a
'write' despite the fact that it does not modify the externally visible
state. It modifies the internal indexing and you are therefore not
allowed to call it concurrently from multiple threads.  As far as I can
tell this is not documented - I found this out the hard way - in a
support incident, Microsoft confirmed that DataTable.Select is
considered a 'write' operation!)


The vast majority of classes in the .NET Framework Class Library just
require you to use them in a single-threaded way, whether you're reading
or writing.  In these cases, the ReaderWriterLock is of no use. The
simple Monitor is likely to be a better bet.


-- 
Ian Griffiths - DevelopMentor
http://www.interact-sw.co.uk/iangblog/

> -----Original Message-----
> From: J. Merrill
> 
> 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(r)  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

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