Small values
For small values ββ(basically any field that can be declared mutable), you can do the following:
private static volatile int backingField; public static int Field { get { return backingField; } set { backingField = value; } }
Big values
With large values, the assignment will not be atomic if the value is greater than 32-bit on a 32-bit machine or 64-bit on a 64-bit machine. See ECMA 335 12.6.6 . Therefore, for reference types and most built-in value types, the assignment is atomic, however if you have a large structure, for example:
struct BigStruct { public long value1, valuea0a, valuea0b, valuea0c, valuea0d, valuea0e; public long value2, valuea0f, valuea0g, valuea0h, valuea0i, valuea0j; public long value3; }
In this case, you will need some kind of lock around the get accessor. You can use ReaderWriterLockSlim for this, as I demonstrated below. Joe Duffy tips for using ReaderWriterLockSlim vs ReaderWriterLock :
private static BigStruct notSafeField; private static readonly ReaderWriterLockSlim slimLock = new ReaderWriterLockSlim(); public static BigStruct Safe { get { slimLock.EnterReadLock(); var returnValue = notSafeField; slimLock.ExitReadLock(); return returnValue; } set { slimLock.EnterWriteLock(); notSafeField = value; slimLock.ExitWriteLock(); } }
Insecure Get-Accessor Demo
Here is the code I used to show the lack of atomicity when not using lock in get-accessor:
private static readonly object mutexLock = new object(); private static BigStruct notSafeField; public static BigStruct NotSafe { get { // this operation is not atomic and not safe return notSafeField; } set { lock (mutexLock) { notSafeField = value; } } } public static void Main(string[] args) { var t = new Thread(() => { while (true) { var current = NotSafe; if (current.value2 != (current.value1 * 2) || current.value3 != (current.value1 * 5)) { throw new Exception(String.Format("{0},{1},{2}", current.value1, current.value2, current.value3)); } } }); t.Start(); for(int i=0; i<50; ++i) { var w = new Thread((state) => { while(true) { var index = (int) state; var newvalue = new BigStruct(); newvalue.value1 = index; newvalue.value2 = index * 2; newvalue.value3 = index * 5; NotSafe = newvalue; } }); w.Start(i); } Console.ReadLine(); }