Question about instatiating a static bo list

Question about instatiating a static bo list

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


dstarkey posted on Tuesday, September 19, 2006

The project tracker application has an instance where a roles object is built as a static list and used throughout the class.  What happen when/if two or more users try to access this object at approximately the same time?  Imagine the roles object as being a larger object so that it would take more time to build initially?  Do both user instances try to build the list??  I would like to know what happens in this case?  Thanks for your help.

Don

ajj3085 replied on Tuesday, September 19, 2006

Each user would have the code running locally and thus would have their own seperate instances of that list.  Neither instance would know about the other.

skagen00 replied on Tuesday, September 19, 2006

I don't have the Project Tracker in front of me - it may not give consideration to thread safety since it's just a simple application. It being in many respects a singleton, there are different ways to make it thread safe and I recently was referencing an on-line article on this.

Here is a URL that describes making a singleton thread-safe through a sequence of examples:

http://www.yoda.arachsys.com/csharp/singleton.html 

 

Edit: I'm living in the Web world right now so that's where my comments are coming from - Andy is correct w/ respect to Windows.

dstarkey replied on Tuesday, September 19, 2006

I am referring to a  web application.  I believe that this static list would be shared by all users, rather than built for each user.  Please correct me if I am wrong.

skagen00 replied on Tuesday, September 19, 2006

On a side note, if you are using an application server, the singleton does persist on the application server between remoting calls (after it gets created for the first time on the app server).

(This is something that I didn't know for sure and did a test some time back to verify it).

---

Rocky, just how expensive is it to do this lock? You've mentioned it a few times now. If I have a simple "namevaluelist" type with only 50 records or so, am I better off just letting the object get created twice?

RockfordLhotka replied on Tuesday, September 19, 2006

skagen00:

Rocky, just how expensive is it to do this lock? You've mentioned it a few times now. If I have a simple "namevaluelist" type with only 50 records or so, am I better off just letting the object get created twice?



Locking is expensive, and becomes more expensive with more users, and with increased use of the item being locked. So it is impossible to give any objective number, because too many factors enter into the equation.

But suppose your shared object was used on every page. And suppose you were handling 50 requests per second. Some of those requests would be delayed, waiting for the lock, and the result is a performance hit. If this happens enough, a queue can develop as threads wait for the lock, compounding the problem. If this happens enough, scalability (throughput) gets hurt as well.

On the other hand, if your shared object is used only on a few pages, that most users aren't using at the same time, then the issue becomes less critical.

You also need to evaluate how often the shared object needs to be recreated. If it is created once when the AppDomain comes up, and tends to remain in memory and unchanged for hours, days, weeks - then the cost of a possible one-time duplicate load seems totally trivial.

On the other hand, if the object gets flushed on a regular basis, every few minutes or something, then the cost (and odds) of a duplicate load become worse.

RockfordLhotka replied on Tuesday, September 19, 2006

A static/Shared field is a per-AppDomain construct.

In any smart client scenario, it isn't shared across 2 or more users, because there can only be one user of an AppDomain in that case.

In a web server scenario, the field is shared across all users of the AppDomain, which really means the virtual root. So in this case threading issues do matter.

My implementation in the book avoids locking, but can end up constructing the object multiple times. This was a concious choice on my part, because locking is expensive and multiple creation of the object is unlikely to occur and wouldn't cause any harm were it to happen.

If the object in question is very expensive to create, then the equation could change. You might choose to implement locking and pay that continual price to avoid the possibility of creating multiple instances of the object.

Let's be clear. In my implementation, if 2 users hit the web site at the same time, and no Roles object had previously been loaded, then they could both attempt to load the Roles object at the same time. Since I have no locking, but threads could detect that _roles is Nothing/null, and both could call Roles.GetRoles(), resulting in the object being created/loaded twice. But (and this is important), both threads would set _roles, and the slower thread's version of Roles would be kept in that field. Any subsequent threads (even a millisecond later) would not create/load a new object, because _roles wouldn't be null.

So the chance of a duplicate load is very small. And since Roles is very static data, the duplicate objects would almost certainly be identical, so no harm would be done. Both threads would get the same result, albiet with different object instances.

It is also important to realize that the faster thread (the one that set _roles first) would use and then release its reference to the Roles object it created. That object would then be destroyed, because any and all other threads would be using the _roles value set by the slower thread. In other words, the duplicate object would exist only for a fraction of a second.

But your issue could be different, because the cost of creating the shared object might be very high. You have to weigh that against the cost of using locking on each and every access to the object. If the object in question is used by many or most of your pages, this could cause a scalability/performance issue - and you need to be aware of that up front.

To implement locking isn't hard - just alter the code in ProjectTracker with this:

  Private Shared mList As RoleList
  Private Shared mListLock As New Object

  Public Shared Function GetList() As RoleList

    SyncLock mListLock
      If mList Is Nothing Then
        mList = DataPortal.Fetch(Of RoleList) _
          (New Criteria(GetType(RoleList)))
      End If
      Return mList
    End SyncLock

  End Function

This ensures that only one thread can execute the factory method at a time, so only one object will be created.

Copyright (c) Marimer LLC