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