views:

44

answers:

1

Consider the following situation: I'm using the Application object in ASP.NET to store a collection(List(of MyObject)) that is being accessed concurrently by several users. While I understand that reading from the Application object is thread safe, I'm wonder how I should make this code thread safe:

objList = Application("GlobalList")

objList.add(AnotherValue)

application("GlobalList") = objList

or

objList = Application("GlobalList")

dim PrunedList as MyObject() = (from o as MyObject in objList where o.SomeProperty = SomeValue).ToArray()

objList.Clear()

For each PrunedListObject as MyObject in PrunedList
   objList.add(PrunedListObject)
next

application("GlobalList") = objList

I read a little about Application.Lock() which basically is a mutex but I worry about the performance impact blocking other threads while manipulating Application("GlobalList") Is Application.Lock() the correct approach?

+2  A: 

I'm not an expert in ASP.NET specifically, but I did use it for a few years. Pretty much the Application storage is there for some sense of backwards compatibility with classic ASP. You would need try/finally blocks to lock and unlock and it's still not nearly as flexible as using some of the other locking mechanisms in .NET that were not there in classic ASP.

In your example, Lock/Unlock would need to be very broad because even after you've grabbed "GlobalList" multiple threads writing to this collection at the same time will still cause concurrency problems.

But in general, any multi-threaded read/write access to a collection is inherently unsafe. You would have the same problem with any collection. But using static fields, you could have multiple threads accessing individual values in a strongly typed fashion with no "magic strings" as is required by a dictionary. Also you wouldn't need to lock in many cases.

You could do something like this without using the Application storage at all. Note that you still need to synchronize access to the collection but you don't need to lock/unlock the entire application state dictionary.

Private Shared GlobalList As New List(Of Foo)()

...

SyncLock GlobalList
    // Only one thread can proceed here at a time
End SyncLock

If performance does become impacted due to multiple readers blocking each other even if no writes are going on, you can switch to using a reader-writer lock. There is an implementation of this in .NET called ReaderWriterLockSlim that allows multiple readers to execute concurrently as long as there are no writers holding the lock. This gives you significantly better performance when there are more readers than writers. Using this kind of lock is a bit trickier though because there is no syntactic sugar like C#'s lock statement or VB's SyncLock.

EDIT

As noted in the comments below, you should always consider the performance implications of whatever locking strategy you use. In particular, ReaderWriterLockSlim may actually degrade performance if there is not a lot of contention between readers. Here's a post on MSDN comparing Monitor and ReaderWriterLockSlim. http://blogs.msdn.com/b/pedram/archive/2007/10/07/a-performance-comparison-of-readerwriterlockslim-with-readerwriterlock.aspx

Josh Einstein
While I in general agree with Josh's answer, in read/write scenario's were the lock is held for a very short period of time, the `lock` statement still outperforms the `ReaderWriterLockSlim` (even with no writes at all). The `ReaderWriterLockSlim` will be useful when the time inside a lock is big enough (according to this http://tinyurl.com/rwlsperformance, the time of calling about 100 non-inlinable, empty methods). Not only makes the user of `lock` your code faster, more importantly, it makes it easier to understand.
Steven
@Steven: I agree. My personal tests show that `ReadWriterLockSlim` is about 5x slower than a plain old `lock` when the critical section can be executed in a quick and snappy fashion. Adding and removing items from a `List` will almost certainly be quick and snappy. Otherwise, this is generally a good answer.
Brian Gideon
Hey guys thanks for the feedback on ReaderWriterLockSlim. I know the old implementation was a dog but I thought they had gotten it much closer to Monitor in terms of performance with the new implementation. In any event, I would always go with the simplest mechanism unless performance testing suggests otherwise.
Josh Einstein