0

I want to access property that can be modified by other code and be sure that access to it is thread safe. Of course, this question was already asked and answered.

However, in my particular situation I have different, specific concerns. First of all, the multi-threaded access/modification scenario is, presumably, a rare occasion, and I wouldn't worry about performance on such an occasion. Also, the property itself is pretty big — it's a jarred array of floats that can get up to 4096 by 4096 in size, and I would like to copy it as rarely as possible. And, finally, I want the class interface to be simple to use — which this solution is not, since it requires the user to implicitly lock a special SyncRoot.

Is there a solution which would make my property thread-safe, wouldn't need additional copying and would allow clients to use the getter (setter is private) without having to remember to lock anything?

Community
  • 1
  • 1
Max Yankov
  • 12,551
  • 12
  • 67
  • 135
  • If it changes rarely, and you are using .NET 4.5, you could use a ReadOnlyCollection and return it in the getter. Then have a separate 'SetUpdatedCollection' method or similar that would discard the old ReadOnlyCollection and create a new one. Use an internal lock object in both the getter and the SetUpdatedCollection method and concurrency would be enforced. – user469104 Oct 28 '14 at 15:08
  • Does the jagged array get 'resized' on other threads or does it only have its contents modified? The resizing case is much trickier, as you don't only have to worry about synchronizing access to the data, but also any cached reads of the size. – Dan Bryant Oct 28 '14 at 16:43
  • @user469104 because of reasons out of my control (Unity3d), I'm locked to .NET 2.0 – Max Yankov Oct 28 '14 at 17:36

2 Answers2

0

If you are going for ease of use, .NET provides built-in thread-safe collection classes that handle the locking for you.

http://msdn.microsoft.com/en-us/library/dd997305%28v=vs.110%29.aspx

You could have a

ConcurrentBag<float[]>

If you roll your own I would worry more about unintentional deadlocks in the future than performance. Deadlocks are a very real risk when you start opening up locking outside of your class.

DVK
  • 2,726
  • 1
  • 17
  • 20
0

Reference operations are atomic. Therefore it is thread-safe to only read from collection if you ensure use captured instance and collection itself is immutable (its elements are not getting changed by whatever means).

ICollection<SomeType> SomeProperty { get; set; }

// good
var property = SomeProperty; // capture
var a = property[1] + ...

// not so good
for(int i = 0; i < SomeProperty.Count; i++) // Count may be taken from new instance
{
    var a = SomeProperty[i]; // really bad
    ...
}

// bad
if(SomeProperty != null) ...

If you want to set new collection, then first fill it and only then set. If you want to change just one element - create new collection, fill it and set.

void AddItem(SomeType item)
{
    var collection = new ICollection<SomeType>(SomeProperty); // copy old content
    collection.Add(item);
    SomeProperty = collection;
}

You should have only one writer as well. More than one required at least some sort of synchronization: lock in AddItem().

There is a problem with IDisposable elements. But this idea (capturing+immutable) should works pretty nice for simple types in scenario with multiple readers and rare writers, because of no need to synchronize.

Community
  • 1
  • 1
Sinatr
  • 20,892
  • 15
  • 90
  • 319