ASP.NET thread safety question

ASP.NET thread safety question

Old forum URL: forums.lhotka.net/forums/t/8769.aspx


tetranz posted on Monday, April 05, 2010

Hi all

I'm starting a new ASP.NET WebForms project. Using CSLA of course. Nearly all my CSLA work until now has been WinForms.

I'd appreciate it if someone could confirm my understanding of basic thread safety. Sorry if this is a bit off topic. It's something I really should know well by now.

Static methods are bad, especially if they have local variables. Right?

In WinForms I often have a "helper" class with a few static methods to do common tasks but in WebForms I need to be careful of anything that would go wrong if the O/S interrupted it and code for another thread / user started the method from the beginning.

But instance methods are generally okay. Right?  So with helper type methods, an easy solution is to make them instance methods. I would obviously need to instantiate the class before calling the method.

Then there is the common data stuff like a list of countries or states or whatever. In WinForms I tend to cache those in static variables and I have to admit that I've never really worried too much about thread safety because my apps haven't been multi-threaded. I've done the typical lazy loading / singleton type of thing. If the variable is null, load it from the db but any future access gets it straight from the static variable.  For this sort of thing, should I continue like that but be careful about it or should I use the ASP.NET cache? Maybe there is not right or wrong answer there. I have seen articles and blog posts etc on how to do the static variable singleton properly in an efficient thread safe manner. eg http://www.yoda.arachsys.com/csharp/singleton.html

I'm leaning towards the ASP.NET cache because I guess that's what it's there for.

Thanks

Ross

ajj3085 replied on Tuesday, April 06, 2010

I think you have it backwards.  Static methods are fine, so long as they don't modify the values of static fields / properties.  If that's true, the method itself is thread safe.

For instance objects, unless you build in thread safety, there is none.  So two threads "using" the same instance will get you into trouble, unless the instance is designed to be thread safe.  Most instance classes are not.

If you implement the Singleton pattern, using a static backing field, you would need to do sycronization yourself.  I think the Asp.Net cache is thread safe, but check the documentation.  Even so you might still trip up.

Consider this code behind:

if ( Cache[ "myKey" ] == null ) {

   Cache[ "myKey" ] = MyBoList.Get();

}

If you have two threads executing that code, thread 1 could pass the if test, then enter the block but be suspended.  Thread 2 could pick up, execute the if and the Get portions and get suspended.. back to thread 1, which would execute Get a second time.

Now, that probably doesn't matter... you've gone from a db hit every call to at most two, and then your results are cached.  But you should be aware.

At least, that's my understanding, so I hope someone will correct me if I"m wrong!

HTH

RockfordLhotka replied on Tuesday, April 06, 2010

Andy is correct.

static fields and properties are problematic, because they are shared across all threads in the appdomain (virtual root), and without locking or other techniques they are never safe.

static methods that don't use global data (atomic, stateless methods) are safe because each method call runs on a different thread with its own call stack so nothing is shared between invocations of the method.

Instances of objects are fine as long as each thread gets its own instance of the type. In other words, if you create an instance of an object and give it exclusively to a thread, that's safe because the data and behavior in that object aren't really multithreaded because they are being used by exactly one thread. This is what ASP.NET itself does when it creates your page object - it hands it to your primary thread and no other thread touches it from that point forward.

Instances of objects that are used by more than one thread is back into multi-threading land, and there is absolutely nothing that makes this automatically safe. It is entirely up to you. Also you must remember that the vast majority of .NET is not threadsafe, including things like ADO.NET. Making this work is really, really hard and should generally be avoided.

Caching object instances in a static field then, combines the two most complex concepts (shared data, shared object instance) and should generally be avoided.

Caching object instances in System.Web.Caching must be done with care too, because the cache maintains references to objects. It doesn't serialize or clone the objects - so it is quite possible for more than one thread to end up interacting with the object instance.

Caching read-only objects is generally fine, because you don't run into concurrency issues. If no thread changes the data, then there's no chance for conflict.

However, caching read-only CSLA objects can be a little tricky because the authorization rules in a ReadOnlyBase object drive off the current principal. As the object switches from thread to thread, the principal changes (each thread has a different HttpContext). Like most of .NET, CSLA isn't threadsafe and you'll get unpredictable results from your authz rules in this scenario. In other words, you can cache a read-only CSLA object as long as it doesn't contain authz rules.

tetranz replied on Tuesday, April 06, 2010

Thanks Rocky and Andy. That's clarified a few things.  I didn't realize that with static methods, each thread gets its own local variables.

I'm mostly concerned with read-only data so the ASP.NET cache is probably my best way to go for most things. The data can be set to expire which is useful.

If seems that you're right, Andy in that the typical use of the cache is to check for the data and then query and insert if it's not there. You don't need to do anything special but, as you say, the db might be hit more than once if several threads want the same data at almost the same time.

Cheers
Ross

CBL replied on Saturday, July 30, 2011

Please forgive the newbie questions, but I thought I had taken the safe and easy route... and now I have discovered my application locks up my server under heavy load.

I have an ASP.NET (Wed Forms) application that uses CSLA and business objects generated by CodeSmith.

Everything seems to work fine, but when under a load I get errors in BusinessBase (CanReadProperty) that from many threads all seem to point to code as not being thread-safe.

Here I know just enough to be dangerous.  I have used code before that spins up threads.  But, here I’m just building a vanilla ASP.NET application, no threading in code.

So my question is in general:  what on earth am I doing wrong?  (Besides using this framework and code generator that are over my head.)  Do I need to do something special in ASP.NET to use CSLA? 

I do have 2005 and 2008 books… but I’m using the latest CodeSmith templates and CSLA 4.1.  I’m down the road on my project (and now in panic mode), so anything you can do to point me in the right direction would be appreciated.

Thank you.

RockfordLhotka replied on Saturday, July 30, 2011

Are you somehow sharing an object instance across threads? This can happen if you use a static field to store an object reference, or if you are using in-proc state and use the Application object. In some cases it can happen with in-proc state and the Session object if a user/browser causes mutliple overlapping calls to the server (usually when the client is using AJAX).

Copyright (c) Marimer LLC