1

After posting this question:

How to lock on an integer in C#?

Many of the answers made me feel that I'm a 'sinner' for using lock in my web apps. I never thought this is a problem (if used wisely), what about you? Do you ever use it in your web applications?

I don't see how a web application can be written without locking, for example if you want to load some data from a database and you want to be sure that no other thread will load it (also for singletons), normally you use locking, for example:

private _locker =  new object();
private YourClass[] _data;
public YourClass[] Data
{
    get
    {
        if(_data == null)
        {
            lock( _locker)
            {
                // get your data
               _data = GetYourData();
            }
        }
        return _data;
    }
}

Is there a problem with this?!

Edit:

Please note that I'm referring to a single server scenario here, for a server farm you need some distributed locking mechanism, but you don't expect every site you create to get millions of hits in a couple of weeks, do you? What if you need locking, should you create your site with that distributed locking, isn't that too much for an application which you have no idea whether it will ever need to be scaled or not? Besides computers have gotten really fast these days, one server can handle tons of traffic and this has been proven so many times, some examples are plentyoffish.com and this very site you're using right now, do some googling and I'm sure you'll come across so many others.

Community
  • 1
  • 1
Waleed Eissa
  • 10,283
  • 16
  • 60
  • 82
  • This implementation of the DCL is broken - _data needs to be declared volatile, and you need another nullity check. This sort of this is precisely why I prefer simple locking. – Jon Skeet Apr 23 '09 at 14:49

6 Answers6

11

If you use a lock to try to control access to a remote resource (e.g. something from the database) then you'll have problems when you try to scale to more servers.

If you just want to have an AppDomain-specific lock (e.g. for a cache) then it makes perfect sense.

I disagree with your implied assertion that web applications can't be written without locking (at the web server level) though. It really depends on the application - usually database contention is handled at the database rather than the web server, precisely so that you can have multiple machines in your web tier.

For singletons it makes a certain amount of sense, but I rarely use singletons anyway...

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • This is true but for an application running on a single machine, I don't see a problem – Waleed Eissa Apr 23 '09 at 12:53
  • If you don't intend to scale out, then fine - but still in many cases you don't need to lock anything anyway. Web requests are often embarrassingly parallelizable, without any locking. – Jon Skeet Apr 23 '09 at 13:59
  • It's not that I don't intend to scale out, the point is it might take ages until I need to, so why complicate things too early, when I run into this, sure I'll drop this simple 'local' locking and look into some other locking mechanism, until then I'm applying both KISS and YAGNI :) – Waleed Eissa Apr 23 '09 at 14:13
  • Just to add, I try to avoid locking (and all the headache that comes with it, dead locks .. etc) as much as I can, but sometimes there's no other way but to lock – Waleed Eissa Apr 23 '09 at 14:16
  • Sometimes - it's just not *that* frequent in web applications. The idea that you *can't* build a web application without locking at the server side just seems a bit of an overstatement. – Jon Skeet Apr 23 '09 at 14:27
  • @Jon Skeet The issue I've had in .net is when using Collections/Arrays that are in the Cache ... when they are removed from Cache when being used elsewhere ... Which I have seemed to have fixed by locking on collection.Syncroot while using it. – Chad Grant Apr 24 '09 at 02:09
3

Yes, you need to check for the data once more. Known as a double check lock. http://en.wikipedia.org/wiki/Double_checked_locking_pattern

Theoretically, a second thread could get past your first null check before your lock is created.

    if(_data == null)
    {
        lock( _locker)
        {
            if (_data == null) {
              // get your data
              _data = GetYourData();
           }
        }
    }

Bad idea to do this in a web app unless you really, really know what you're doing.

I would look into Upgradeable Locks http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.enterupgradeablereadlock.aspx

Chad Grant
  • 44,326
  • 9
  • 65
  • 80
  • Yep. And to be really safe _data should be marked as volatile so it doesn't get cached by the CPU. – Steve Apr 23 '09 at 13:09
  • Actually this is what I do, I don't use single checking as in the example I mentioned, but my question wasn't about this so there was no need to use it ... – Waleed Eissa Apr 23 '09 at 13:16
  • I wouldn't bother using DCL unless I had good profile information to suggest that it was really necessary. It's *far* too easy to get wrong. – Jon Skeet Apr 23 '09 at 14:48
2

I don't know how you do data-access, but I've never found it needed to lock the database for one request only. I'm not sure, but I could imagine you'd try to solve certain problems with a Microsoft Access database, but thats just because it's not a good database system to use for a website (or just anything which leaves your local desktop).

Davy Landman
  • 15,109
  • 6
  • 49
  • 73
1

Locking a local contested resource at some point within a request is fine (although rare). Locking a request and trying to hold the lock across several requests is not really going to work too well. Even if you can get it to work in a single server environment if you ever have to scale to a multi-server environment then it's just not going to work the way you expect.

Steve Willcock
  • 26,111
  • 4
  • 43
  • 40
  • Again my question was about a single server scenario, sure this won't work on a server farm (some distributed locking mechanism is needed for this). The point here is not to lock for one or several requests, it's to lock while doing an action, otherwise what's the point in locking in the first place? – Waleed Eissa Apr 23 '09 at 13:00
  • Ok, well with those caveats in place I'd say it's perfectly ok to use locking for locally contested resources :) – Steve Willcock Apr 23 '09 at 13:06
0

The remote resource that you try to access should be in charge of the locking. As someone already pointed out, locks are process-wide, and as soon as you scale up your locks will just fail to work.

Databases also should do all the locking you need. It's one of the main requirements for a DBMS: data integrity.

bayer
  • 6,854
  • 24
  • 35
  • Are you going to let every request hit your database? Besides what about locking across multiple database server, if we're going to talk about scaling then we should take all the possibilities, don't we? – Waleed Eissa Apr 23 '09 at 13:12
  • You can actually use multiple db servers and still use their locking capabilities (eg. sharding). If you don't want to hit the database everytime and use a cache, this cache should be responsible for locking. All I'm saying is this: locking adds another axis of complexity to your application. Try to avoid it as long as possible and shift problem to the places where it is already solved. (e.g. dbms) – bayer Apr 24 '09 at 08:42
0

I've never needed to use any synchronization mechanism on any of my webapps. Unless you're dealing with say, a raw XML file that multiple sessions are changing, I can't see the need for it. Like most people here have said - your database will take care of that for you. Updates, queries, what have you, database systems (at least ones you are likely to use with ASP.NET) take care of synchronization for you.

Rob
  • 25,984
  • 32
  • 109
  • 155
  • I assume you're talking about applications with zero cache that hit the database with every request, but those don't scale very well .. with caching you definitely have to use locking – Waleed Eissa Apr 23 '09 at 13:23
  • Well, as David Schmitt said in his answer, you're probably better off using ASP.NET's built in caching infrastructure. If you're rolling your own caching infrastructure, I'd say it's a bad idea to reinvent the wheel, since your locking code is most likely going to be far more error prone. – Rob Apr 23 '09 at 13:27