CSLA not Thread-safe?

CSLA not Thread-safe?

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


tbaldridge posted on Monday, February 28, 2011

 

I have a program that we'd like to multi-thread at a certain point. We're using CSLA for our business rules. At a one location of our program we are iterating over a BusinessList object and running some sanity checks against the data one row at a time. When we up the row count to about 10k rows it takes some time to run the process (about a minute). Naturally this sounds like a perfect place to use a bit of TPL and make this multi-threaded.

I've done a fair amount of multithreaded work through the years, so I understand the pitfalls of switching from single to multithreaded code. I was surprised to find that the code bombed within the CSLA routines themselves. It seems to be related to the code behind the CSLA PropertyInfo classes.

All of our business object properties are defined like this:

    public static readonly PropertyInfo<string> MyTextProperty = RegisterProperty<string>(c => c.MyText); 
public string MyText {
get
{ return GetProperty(MyTextProperty); }
set
{ SetProperty(MyTextProperty, value); }
}

Is there something I need to know about multithreading and CSLA? Are there any caveats that aren't found in any written documentation (I haven't found anything as of yet).

BTW: the way I implemented my multi-threading via throwing all the rows into a ConcurrentBag and then spawning 5 or so tasks that just grab objects from the bag till the bag is empty. So I don't think the problem is in my code.

 

ajj3085 replied on Monday, February 28, 2011

Csla is not thread safe. I believe Rocky tries to do the normal .Net thread safety; static members are, instance members are not, but don't take that as the official answer..

What version of Csla are you using?  If you're on 4.x, you can create an async rule.  That won't permit you to interact with the object in any other thread, but you can use it to disable your UI while the rule runs in the background.  There's an IsBusy property that tells you if a rule is still running in the background or not.

RockfordLhotka replied on Monday, February 28, 2011

Andy is correct, CSLA .NET is not thread safe. There are numerous threads about this on the forum from over the years.

It is also the case that the vast majority of .NET is not threadsafe. Very few parts of .NET are threadsafe, and they are documented in MSDN when they happen, because they are pretty rare.

The basic reason .NET isn't generally threadsafe is that the perf cost of being threadsafe is usually very high. This is also true for CSLA.

Sure, I might be able to make parts of CSLA threadsafe (where it wouldn't run afoul of .NET BCL limitations), but that'd require locking code in many sensitive places - again leading to the same perf issues Microsoft (and I) avoid by not being broadly threadsafe.

At some point this may change. As Microsoft rolls out the TPL to all its platforms, and some of the v.next language features for C# and VB they talked abotu at the last PDC become broadly available, it becomes more realistic to think about reworking some of these implementation details.

But right now those features aren't on SL or WP7, much less MonoTouch/MonoDroid...

tbaldridge replied on Tuesday, March 01, 2011

So are there any parts of CSLA that are not reentrant? Can I load up 10 seperate objects and manipulate them on 10 seperate threads, saving them back to the DB in those same threads? Or is there some sort of CSLA background state that I need to be aware of.

I would agree that I can't expect CSLA to handle 10 threads inserting/removing records from the same collection of BOs. But I would not expect CSLA to blow up on me when loading 10 objects from 10 threads. But from what I'm reading of the other forum posts, that may not be possible either.

As an aside note, where in the documentation can I find this information? I would expect something as basic as thread safety to be noted somewhere.

RockfordLhotka replied on Tuesday, March 01, 2011

CSLA business objects are, first and foremost, bindable objects. This means they are subject to the same rules for threading as the UI technologies they bind to.

WPF, Windows Forms, Silverlight, WP7 - none of these technologies allow multiple threads to interact with UI elements.

Because CSLA objects raise data binding events, they similarly don't support multiple threads - not in small part because that would result in those events being raised on background threads, and that would cause a cross-thread exception.

Additionally, objects within an object graph interact with each other using these same events. The ChildChanged event model, for example, cascades up through the entire object graph and is often used to run business rules at various levels in the object graph. Those events are all raised on whatever thread was running when the original PropertyChanged, CollectionChanged, or ListChanged event was raised.

Taken together, this means (in general) that the following are true:

  1. Any changes made to objects within an object graph must be made by exactly one thread at a time - multiple threads can't mutate objects in the same object graph at the same time
  2. Any changes made to an object graph that is bound to a UI must be made by the UI thread - use of any other thread will result in a cross-threading exception from the UI data binding technology

In a web or server environment, where different threads might be running in the security contexts of multiple concurrent users there's one more thing to consider:

  1. Authorization rules run as properties are read, and those are obviously sensitive to the current user's principal. So attempts to interact with the same object (even for reading) across multiple user threads will either fail or result in horrific performance (due to security context switching)

I'd probably document all this in much more detail if the issue came up more than once every 12-18 months. And maybe it will come up more often in .NET v.next when threading is more accessible/common - but it just hasn't been worth the effort to do a lot of documentation around this for one person every 1-2 years...

JCardina replied on Wednesday, March 02, 2011

tbaldridge
Can I load up 10 seperate objects and manipulate them on 10 seperate threads, saving them back to the DB in those same threads?

 

Definitely with the 4.1 version of Csla because my unit test for one object does exactly this without fail.  (No UI involved though)

RockfordLhotka replied on Wednesday, March 02, 2011

JCardina

[quote user="tbaldridge"]Can I load up 10 seperate objects and manipulate them on 10 seperate threads, saving them back to the DB in those same threads?

 

Definitely with the 4.1 version of Csla because my unit test for one object does exactly this without fail.  (No UI involved though)

I believe this can work if there are no rules or behaviors attached to any changed events.

But put a rule on the parent object of a list, then change the items in the list on different threads and I suspect you'll get all sorts of nasty results - race conditions in particular.

 

JCardina replied on Wednesday, March 02, 2011

Yeah I'm talking about a root object with child objects but due to the way visual studio mstest works it fires off all my unit tests for that one object at the same time.  So that object is being instantiated separately on all those test threads, not retrieved once then manipulated from separate tests.

ajj3085 replied on Wednesday, March 02, 2011

So each thread creates an instance and then performs teh test with it, and that's the end of things?  No interaction between threads during the running?

That should work, but that's quite different form the original posting, which discussed putting objects into a ConcurrencyBag and then doing stuff with different threads.  If these are child objects you're putting in the bag than manipulating with different threads, that would likely cause issues.  The parent object listens for events from its children, and children raising events on different threads at the same time probably would cause issues.

JCardina replied on Thursday, March 03, 2011

Andy
So each thread creates an instance and then performs teh test with it, and that's the end of things?  No interaction between threads during the running?

That's how MSTest in Visual studio works.  It runs test in parallel.  You have to jump through hoops to force it to *not* do that.

Andy
but that's quite different form the original posting

I don't see exactly how?  The person who started the thread asked specifically:

"Can I load up 10 seperate objects and manipulate them on 10 seperate threads, saving them back to the DB in those same threads?"

Which is provably working via parallel unit testing.

RockfordLhotka replied on Thursday, March 03, 2011

No, the original post was about a BLB with a lot of items, and using multiple threads to interact with those items.

That's one object graph, with multiple threads - exactly what is NOT allowed.

There should be no problem using multiple threads where each thread interacts with a different object graph. That had BETTER work, since that's what happens on every web and app server :)

RockyRocks replied on Saturday, July 21, 2012

Wow, great info.

I have done a bit of TPLing in one CSLA system, but luckily it was done using a raw List<T> and POCOs in that particular part - and, of course, not adding to/removing from the list in the paralleled code. That seemed to work fine - but I never considered that it wouldn't work if I had used an editable list.

Out of interest, does this restriction apply to Partitioner.Create over a read-only CSLA list (read only root list, with children not having any relations to any other objects), with the parallel code only reading from properties on the children? Is it only editing events that cause problems or would there be restrictions in reading managed properties because of maybe authorisation related code?

I could avoid managed properties I suppose, using private backing variables if I only use that list on full .NET framework and need no authorisation. Is that a wise or necessary precaution?

Thanks.

Copyright (c) Marimer LLC