views:

829

answers:

3

I like to use objects which sync itself using a private object which is locked when the property is changed. Is there any generic way to achieve this? My code looks always like this for each property (with one locker object)

private Object locker = new Object();
private int x; 
    public int X
    {
    get {return x;} 
    set{
        lock(locker){x=value;}
    }

Is thee an easier way to achieved thread-safe modification of properties.

+7  A: 

Your code shouldn't look like that - you should lock on the get as well. Otherwise threads fetching data may not get the most recent value, for complicated memory model reasons.

But no, I don't know of any ways around this. You could do odd stuff with lambda expressions and extension methods, but it would be overkill IMO.

You should also strongly consider whether you really want the individual properties to be thread-safe. It may be the right thing to do - but I find that usually I don't need most types to be thread-safe. Only a few types need to directly know about threading, and they then take out appropriate locks while they're using the object, rather than the object doing the locking itself. It does depend on what you're doing though.

Another alternative for some cases is to use immutable types - that's nice when you can do it, although if you need one thread to see the changes made in another you'll need some sort of volatility or synchronization.

Jon Skeet
+1 absolutely correct. In such a case (simple getter/setter scenario) I would use the Interlocked class.
Michael Damatov
@Toro: At that point you need to think differently about different property types though, and use locking for some other properties. Another alternative would be volatile variables. Personally, unless I see a bottleneck, I prefer to apply the consistent approach of locking - *if* appropriate!
Jon Skeet
@Jon Skeet: is it correct to use the same lock object for each property in a class? Do we care to lock access to X when Y being updated on another thread?
vg1890
@vg1890: That depends on what semantics you want. Do you want the changes to be observable independently? Again, locking individual properties often isn't really where you want to be headed in the first place.
Jon Skeet
+3  A: 

Not to be an 'enabler', but if you decide this is definitely the design you want, and you find yourself typing these properties repetitively you might want to save yourself a few keystrokes and write a little code snippet to speed up the process of adding them.

    <?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"&gt;
    <CodeSnippet Format="1.0.0">
     <Header>
      <Title>prop</Title>
      <Shortcut>propso</Shortcut>
      <Description>Locking property for SO</Description>
      <Author>TheMissingLinq</Author>
      <SnippetTypes>
       <SnippetType>Expansion</SnippetType>
      </SnippetTypes>
     </Header>
     <Snippet>
      <Declarations>
       <Literal>
        <ID>type</ID>
        <ToolTip>Property type</ToolTip>
        <Default>int</Default>
       </Literal>
       <Literal>
        <ID>property</ID>
        <ToolTip>Property name</ToolTip>
        <Default>MyProperty</Default>
       </Literal>
       <Literal>
        <ID>field</ID>
        <ToolTip>Field Name</ToolTip>
        <Default>myField</Default>
       </Literal>
      </Declarations>
      <Code Language="csharp">
      <![CDATA[private $type$ $field$;
       public $type$ $property$ 
       {
        get
        {
         lock(locker) { return this.$field$; }
        }
        set
        { 
         lock(locker) { this.$field$ = value; } 
        }
       }
      $end$]]>
      </Code>
     </Snippet>
    </CodeSnippet>
</CodeSnippets>
TheMissingLINQ
+1  A: 

I keep finding myself surprised at what C# can do with the new C# 3.0 features. I was going to throw something out there that I thought would be so-so, but it turns out to be better than I hoped for. Here 'tis.

Make an object to hold all the values (let's just call it a "value holder" ... not to be confused with any other usage of that term though). It has nothing but C# automatic properties. Then make another object which gives access to the value holder. Call the second object the "SynchronicityHandler" (sucky term, but will get the concept across).

Let the SynchronicityHandler do the locking. It can now be generic. So here's what you get:

public class PersonValueHolder
{
     public string FirstName { get; set; }
     public string LastName { get; set; }
     public bool HasCollegeDegree { get; set; }
}

public class SyncronicityHandler<T>
{
     private object locker = new object();

     private T valueHolder;

     public SynchronicityHandler(T theValueHolder)
     {
          this.valueHolder = theValueHolder;
     }

     public void WorkWithValueHolderSafely(Action<T> yourAction)
     {
          lock(locker)
          {
               yourAction(valueHolder);
          }
     }
}

Here's an example of how you'd call it:

var myPerson = new SynchronicityHandler(new PersonValueHolder());

// Safely setting values
myPerson.WorkWithValueHolderSafely( p => 
     {
          p.FirstName = "Douglas";
          p.LastName = "Adams";
          p.HasCollegeDegree = true;
     });

// Safely getting values (this syntax could be improved with a little effort)
string theFirstName = null;

myPerson.WorkWithValueHolderSafely( p=> theFirstName = p.FirstName);

Console.Writeline("Name is: " + theFirstName); // Outputs "Name is: Douglass".

Really, now that I think about it, the "value holder" doesn't have to be just automatic properties. It can be any object.

Charlie Flowers
Wicked idea - thanks!
weismat
You bet. I'd love to hear how it works out for you.
Charlie Flowers