3

I have a list, to which I write once in every update Loop and then I spawn some tasks which create read that List and create a duplicate to manipulate that data. More or less it's List.ToList() call to create a new list instead of using it by reference. Each task manipulates that data in it's own and produces it's results. Currently I am using a traditional lock in the form of

lock(LockObject){
//write stuff
}

when writing and

lock(LockObject){
localList=List.ToList();
}

when reading.

Would using the ReaderWriterLockSlim object instead of the way I am doing it now provide me with any benefits speed-wise? Also is the ToList() method considered a read in this case?

Clarification Edit

  1. The readers create a copy because they manipulate the data differently, each one of them removes or adds data to the List on their own way. (some might add previous data they still need while others remove data they do not need. Also the update loop occurs once every few seconds so it is common.
  2. Sometimes if the data input is really fast an update/write loop might start before all the readers have completed their processing (but if they get the updated data instead is no problem for me).
  3. Basically the readers are there for presenting current data to others. So if data is changed before they even start presenting them that's ok. As long as they do not try to process data while they are being update (which would probably throw an exception)
3

It depends. Using a reader/writer lock rather than a critical section can be beneficial if read operations are noticeably more common than write operations. But I think you could probably achieve more by changing your application architecture.

If writes are rare, you can probably get much better performance by treating the collection as immutable and producing an entirely new list when it changes. You can then use Interlocked.CompareExchange to update the reference to the list in a thread-safe way. This should prevent readers needing to make a defensive copy (which should be a huge win if reading is more common than writing) and remove the need for locking.

Alternatively, if writing is more common than reading, it may be worth evaluating a ConcurrentStack as a replacement for the list. This provides an atomic ToArray method that can be used to make copies without needing locks. Alternatively, if order isn't important in your list, a ConcurrentBag may perform better.

Edit after clarification

I still think you would be better off copying the list when you modify it, as this allows you to do away with the lock entirely. Even if the readers need to change the list contents during processing, this would be better refactored to use a streaming style, e.g. LINQ to Objects, so that these operations do not actually duplicate the data. See Martin Fowler Refactoring with Loops and Collection Pipelines for more about converting existing code to this style.

Failing that, I imagine you'd see a small gain switching to the reader/writer lock, but unless lock contention is unusually problematic for your application I doubt it'll be noticeable.

  • edited my question with some clarifications – John Demetriou Aug 25 '15 at 8:23
  • Order is important, so concurrent bag is out of the question. During the write operation I am also performing LinQ on the list. Also instead of using interlocked.exchange, Is it not the same if I write the data to a separate list and lock before updating the thread accessed one? – John Demetriou Aug 25 '15 at 8:55
  • Using Interlocked.CompareExchange (I originally linked to the wrong function) allows you to detect the case where another modification has happened to the list while the update is in progress. A lock won't allow this; you'd have to lock it for the entire period you're calculating the update. Of course, if you know that only one thread is updating the list, neither is necessary. – Jules Aug 25 '15 at 9:00
  • Although if using neither, you may need a memory barrier after updates and before reads, to ensure all threads are working on the latest data: msdn.microsoft.com/en-us/library/… – Jules Aug 25 '15 at 9:04
  • yes but from my experience locks are faster than memory barriers, I'm looking into waits to replace the traditional lock with something faster – John Demetriou Aug 25 '15 at 9:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.