Click here to Skip to main content
Click here to Skip to main content

Handy wrapper class for thread-safe property access

By , 21 Feb 2009
 

Introduction

After writing C# threaded applications for a few years, I started to get bored of writing the synchronization code for each property I wanted to make thread-safe. If you want your class to manage the locking in a neat OOP encapsulated way, you must create locking variables and handle access to each property using get { } and set { }.

So came the idea of writing a simple wrapper class to do the dirty work for me. The Synchronized class is my first try at this, and can hopefully be further developed and extended.

I hope this can be of interest to some, and I really do hope to get some feedback to improve and extend my work. :)

Background

The basics to make this work are the use of Generics and type casting overloading. I suggest those who are not familiar with these concepts have a look at the .NET documentation or at one of the many good articles on the web.

Using the code

A typical C# approach to making properties thread-safe would be something like:

internal class MyThreadSafeCass
{
    // *** Lock ***
    private object PropertyLock = new object();
       
    // *** Property ***
    private int m_Property = 0;
        
    // *** Thread-safe access to Property using locking ***
    internal int Property
    {
        get
        {
            lock (PropertyLock)
            {
                return m_Property;
            }
        }
        set
        {
            lock (PropertyLock)
            {
                m_Property = value;
            }
        }
    }
}

Now, every thread in your application can access Property in a thread-safe way.

A class containing a few properties which must be made thread-safe would lead to writing quite some code, and decrease the overall neatness and readability.

Let's have a look at the Synchronized wrapper class. Its definition is quite simple:

// **********************************************
// *** Synchronized access wrapper class V1.0 ***
// **********************************************
// *** (C)2009 S.T.A. snc                     ***
// **********************************************
using System;

namespace STA.Threading
{

   internal class Synchronized<T>
   {
        // *** Locking ***
        private object m_ValueLock;

        // *** Value buffer ***
        private T m_Value;

        // *** Access to value ***
        internal T Value
        {
            get
            {
                lock (m_ValueLock)
                {
                    return m_Value;
                }
            }
            set
            {
                lock (m_ValueLock)
                {
                    m_Value = value;
                }
            }
        }

        // *******************
        // *** Constructor ***
        // *******************
        internal Synchronized()
        {
            m_ValueLock = new object();
        }

        internal Synchronized(T value)
        {
            m_ValueLock = new object();
            Value = value;
        }

        internal Synchronized(T value, object Lock)
        {
            m_ValueLock = Lock;
            Value = value;
        }

        // ********************************
        // *** Type casting overloading ***
        // ********************************
        public static implicit operator T(Synchronized<T> value)
        {
            return value.Value;
        }

    }
}

It makes use of Generics in order to be able to wrap any type, and overloads the implicit type casting to the wrapped type to allow a Synchronized object to be used in place of the wrapped type, where possible.

Now, we can use it to modify our test class:

using STA.Threading;

internal class MyThreadSafeCass
{
    // *** Thread-safe property ***
    internal Synchronized<int> Property = new Synchronized<int>(0);
}

Simple and neat.

What it does and what it does not

A property wrapped in a Synchronized class can be used in many common situations without needing any special syntax, but there are some exceptions. Here is a brief summary of its most common uses:

using STA.Threading;

...

// s1 <- 10
Synchronized<int> s1 = new Synchronized(10);
// s2 <- 0 (deafult for int)
Synchronized<int> s2 = new Synchronized();

s2 = 20; // ERROR: the '=' operator cannot be overloaded, thus
         // you cannot assign a value of type T directly to a
         // Synchronized<T> object

s2.Value = 20; // Valid: s2 <- 20

int sum = s1 + s2: // Valid: s1 and s2 are subject to implicit
                   // type casting to type T, so sum <- 30

s1++; // ERROR: I didn't find a way to overload the ++ and -- unary
      // operators because of a limitation with Generics: you cannot
      // use ++ or -- on generic type T. Hopefully this can be worked
      // around in some way in a future release. Maybe using "where
      // T : ..." ?

s1.Value++; // Valid: s1 <- 11

int TestFunction(int Value)
{
    return Value * 10;
}

int ret = TestFunction(s1); // Valid: s1 is subject to implicit type
                            // casting to type T, so ret <- 110

int.TryParse("50", out s1); // ERROR: out requires a modifiabile
                            // variable, so type casting is not
                            // possible

int.TryParse("50", out s1.Value); // ERROR: a property cannot be
                                  // used with out or ref

int tmp;
int.TryParse("50", out tmp);
s1.Value = tmp;              // Valid: s1 <- 50

...

The biggest limitation with this approach is it's no good with properties of complex types. For example, a Synchronized<DataDet> property will not render calls to the wrapped DataSet's properties or thread-safe methods.

Points of interest

I found the approach to implicit and explicit type casting overloading in C# particularly nice and efficient. Before this project, I only had experience with unary and binary operators overloading, and when I first started looking around in the documentation for some hint as to how to implement my idea, I doubted there would be such an easy solution.

History

  • 2009-02-21 - V1.0 - First release.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Moreno Airoldi
Software Developer S.T.A. snc
Italy Italy
Member
Been coding since I was 10, started out on a Philips game console in pseudo-assembler and then moved on to a C64, C128, and lots of Amigas.
 
Been working in the field of software development for industrial automation since 1989.
 
Now I'm running a small software house together with my wonderful wife. We specialise in the development of software solutions for industrial automation, data acquisition, automated production management and ERP integration with factory automation.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Generalis there any performance issues , is this a replacement for volatile fields.memberBAIJUMAX3 Apr '09 - 16:53 
We have same situation in our project where we need to use minimum 5 properties and these 5 properties are accessed/set by 4 timer callback (executes at every say 1 sec.) functions. Is it good practice put lock statement around all properties , is there any performance issues provided properties are easy to access and simple "sample.prop=4" have to go through a lock behind the scene.
 
why can't we use "volatile" fields instead of locked properties?
 

Cheers
BAIJUMAX
AnswerRe: is there any performance issues , is this a replacement for volatile fields. [modified]memberMoreno Airoldi4 Apr '09 - 1:22 
Hi Baijumax,
 
The volatile keyword does something slightly different from locking: it tells the compiler to generate instructions "as atomic as possible" on the property. This means that in simple cases like the one in my example, volatile should be more than fine. It sure depends on the property's data type and word alignment of the architecture you're working on anyway. So it's not a substitute for locking in all cases.
 
In terms of performace, you are absolutely right: volatile is much more performing.
 
About your project, if the 5 properties are all accessed separatedly, then volatile should be ok to ensure a basic thread-safety.
 
If they are to be accessed together, then it is not. For example, if your timer callbacks modify more than one property and you want any other thread to read all of the properties in a thread-safe way, you must use locking. A rough example could be (don't mind the horrible code, it's just an example :P):
 
internal Class MyThreadSafeClass
{
  internal object MyLock = new object();
 
  internal int Property1 = 0;
  internal int Property2 = 0;
  internal int Property3 = 0;
  internal int Property4 = 0;
  internal int Property5 = 0;
}
 
internal MyThreadSafeClass MyInstance = new MyThreadSafeClass();
 
...
 
internal void MyTimerCallback1()
{
  lock (MyInstance.MyLock)
  {
    MyInstance.Property1 = 10;
    MyInstance.Property2 = 20;
    ...
  }
}
 

internal void MyTimerCallback2()
{
  lock (MyInstance.MyLock)
  {
    MyInstance.Property1 = 100;
    MyInstance.Property2 = 200;
    ...
  }
}
 
...
 
internal void MyReadRoutineOnAnotherThread()
{
  int[] Values = new int[5];
 
  lock (MyInstance.MyLock)
  {
    Values[0] = MyInstance.Property1;
    Values[1] = MyInstance.Property2;
    ...
  }
 
  // Here we can use the values and be sure they are consistent
  ...
}
 
The idea (dream) behind my Synchronized class is to eventually find a way to do something like:
 
internal Class MyThreadSafeClass
{
  private object MyLock = new object();
 
  internal Synchronized<int> Property1 = new Synchronized<int>(0, MyLock);
  internal Synchronized<int> Property2 = new Synchronized<int>(0, MyLock);
  internal Synchronized<int> Property3 = new Synchronized<int>(0, MyLock);
  internal Synchronized<int> Property4 = new Synchronized<int>(0, MyLock);
  internal Synchronized<int> Property5 = new Synchronized<int>(0, MyLock);
}
 
internal MyThreadSafeClass MyInstance = new MyThreadSafeClass();
 
...
 
internal void MyTimerCallback1()
{
  MyInstance.Property1 = 10;
  MyInstance.Property2 = 20;
  ...
}
 

internal void MyTimerCallback2()
{
  MyInstance.Property1 = 100;
  MyInstance.Property2 = 200;
  ...
}
 
...
 
internal void MyReadRoutineOnAnotherThread()
{
  int[] Values = new int[5];
 
  Values[0] = MyInstance.Property1;
  Values[1] = MyInstance.Property2;
  ...
}
 
This would NOT be thread-safe with the current version of my Synchronized class, since accesses to properties would be locked separatedly!
 
Cheers! Smile | :)
 
2+2=5 for very large amounts of 2
(always loved that one hehe!)
modified on Saturday, April 4, 2009 7:29 AM

GeneralRe: is there any performance issues , is this a replacement for volatile fields. [modified]memberBAIJUMAX4 Apr '09 - 6:20 
In my case all are properties independent of each other (see below sample code snippet) . So can we use volatile? I believe it’s not that’s what my googled searched pages says opposed to MSDN documentation about volatile.
 
Class Test
{
Private Timer timer1 = new Timer();
Private Timer timer2 = new Timer();
………………………………….
Private bool serverIsResponding = false;
 
///// Thread 1 , calls at every 1 sec
Private void TimerCallBack1(……..)
{
If(serverIsResponding)
{
//register request for a data.
}
}
 
///// Thread 2 , calls at every 30 sec
Private void TimerCallBack2(……..)
{
If(!serverIsResponding)
{
/// unregister request for data , cleanup ………
}
 
}

//// Thread 3, server heart beat message handler ( tibco rv message handler for example)
Private void OnServerMessage(………..)
{
If(……..) serverIsResponding = false;
Else serverIsResponding = true;
}
 
}
 
In the above sample ‘serverIsResponding’ member variable used in all the three callbacks executed in a different thread.
 
Solutions,
 
#1 add a property “ServerIsResponding” and apply lock on set/get. [performance issue.]
 
#2 make ‘serverIsResponding’ as volatile. [not sure about this solution].
 
#3 use your class. I have a doubt here, if create a object (ref object) don’t we have to apply a lock on that object to ensure thread safety.I’m here worried about thread local caching of newly created ref object.
 
Let me know your thoughts.
 
modified on Saturday, April 4, 2009 1:33 PM

GeneralRe: is there any performance issues , is this a replacement for volatile fields.memberMoreno Airoldi4 Apr '09 - 23:41 
Well my opinion is that in your case you might even do without any kind of locking, since the property is a boolean, so you won't suffer from thread safety issues! Adding volatile in your case is ok, but it won't do anything really useful.
 
If you are worried about performance issues, my best suggestion is to leave the code as it is, while if you want to be "strict" about thread-safety, you can either add locking or use my class: both will do fine.
 
It's also interesting to note that you are not accessing the property continuously in your code, but only once in a while (when the timers or heartbeat are triggered), and only to quickly change its value. So if you should use locking (or my class) you won't suffer from any significant performance issue.
 
Locking can introduce performance issues only if you perform significant computations inside the lock (thus blocking all other threads which are trying to access the resource for a "long" time).
 
To answer to your question in point #3, you don't have to add any locking on the object reference if you use my class: the incapsulated locking will do all the work for you.
 
Hope this can be of help. Smile | :)
 
2+2=5 for very large amounts of 2
(always loved that one hehe!)

GeneralRe: is there any performance issues , is this a replacement for volatile fields.memberBAIJUMAX5 Apr '09 - 19:32 
////It's also interesting to note that you are not accessing the property continuously in your code,///
 
in fact timer callbacks executes in every 1 sec,30 secs respectively [ means lock statement executes in every 1 sec etc.. ]....
 
Well ,by adding a lock we can argue that our application ensures accuracy and this rules over performance Smile | :) .
GeneralInstance class propertymemberonidsuit25 Mar '09 - 16:26 
Hi,
 
Would you need to synchronise properties in an instance class? Even if you have a multithreaded application, I would have thought that if a thread has an instance of the class (i.e. not a static class) then that instances properties would be thread safe (assuming that the properties are not declared as static)?
 
Thanks,
Dino
GeneralRe: Instance class propertymemberMoreno Airoldi26 Mar '09 - 2:16 
Hi Dino,
 
Class instances are not thread safe by default, they are not "owned" by any thread. They reside in the application's heap and all threads can reference it.
 
So, it's up to us poor programmers to implement locking and make things thread safe. Smile | :)
 
As you can see in comments by other people to this article, in real life situations it usually takes a finer/more complex approach than the one described here, but for specific problems this can still be useful, in my opinion.
 
2+2=5 for very large amounts of 2
(always loved that one hehe!)

GeneralQuestionmemberPIEBALDconsult22 Feb '09 - 12:02 
I didn't read the code too closely, so excuse me if I misunderstood.
 
Will each "property" have its own m_ValueLock? That's generally a bad idea; instead each instance should have one item on which to lock to avoid deadlocks.
 
Overall, I would rather write all the necessary code to perform the locking properly. I would not try to cut corners here.
GeneralRe: QuestionmemberMoreno Airoldi23 Feb '09 - 1:13 
Hi, you did read correctly. I think I will get this question asked many times, and I would like to be clear on this subject: this Synchronized class, in its current form, is not that useful in real life applications!
 
Of course the best way to handle locking remains writing the proper code, or using methods, as I said in my reply to Omer's post.
 
The goal of this excercise is simply to work on the idea of having a wrapper class for property locking. I find this a very interesting idea - imagine being able to wrap a complex type property and make it automatically thread safe (by which I mean making calls to its parameters and methods thread safe). Of course it will most probably take changes to the compiler and/or runtime to attain that, but still I think it's quite stimulating to work in that direction.
 
I'm almost done with the next version of this class, in which I will override binary and unary operators, in order to make them thread-safe too. Unluckily, I still can't see a way to handle more complex scenarios like locking a set of properties or a complex type property, as I said.
 
I think feedback from all ppl here will be really useful, and I'm confident I will learn a lot from this exercise! Big Grin | :-D
 
2+2=5 for very large amounts of 2
(always loved that one hehe!)

GeneralRe: Questionmemberonidsuit31 Mar '09 - 14:54 
Hi Moreno,
 
I understand that class instances are allocated on the heap. Would the following implementation of MyCass require a lock considering that each thread does not use the same instance of MyClass but uses its own instance of MyClass?
 
class Program
{
static void Main(string[] args)
{
Thread[] threads = new Thread[100000];
 
for (int i = 0; i <= 999999; i++)
{
MyCass c = new MyCass();
Thread t = new Thread(new ThreadStart(c.DoSomething));
t.Start();
threads[i] = t;
}
 
foreach (Thread t in threads)
t.Join();
 
Console.WriteLine("finished");
Console.ReadLine();
}
}
 
public class MyCass
{
private int m_Property = 0;
 
public int Property
{
get
{
return m_Property;
}
set
{
m_Property = value;
}
}
 
public void DoSomething()
{
Console.WriteLine("Start DoSomething(" + Thread.CurrentThread.GetHashCode() + ")");
Console.WriteLine("Thread " + Thread.CurrentThread.GetHashCode() + " Property value is " + Property); //should always be 0
Property = Thread.CurrentThread.GetHashCode();
Console.WriteLine("Thread " + Thread.CurrentThread.GetHashCode() + " Property value is now " + Property);
Console.WriteLine("End DoSomething(" + Thread.CurrentThread.GetHashCode() + ")");
}
}
 
Thanks,
Dino

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 21 Feb 2009
Article Copyright 2009 by Moreno Airoldi
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid