It completely depends on the type, T
.
If you are able to place a class
constraint on T
then you don't need to do anything in this particular case. Reference assignments are atomic. This means that you can't have a partial or corrupted write to the underlying variable.
Same thing goes for reads. You won't be able to read a reference that is partially written.
If T
is a struct, then only the following structures can be read/assigned atomically (according to section 12.5 of the C# specification, emphasis mine, also justifies the above statement):
Reads and writes of the following data types shall be atomic: bool, char, byte, sbyte, short, ushort, uint, int, float, and reference
types. In addition, reads and writes of enum types with an
underlying type in the previous list shall also be atomic. Reads and
writes of other types, including long, ulong, double, and decimal, as
well as user-defined types, need not be atomic. Aside from the library
functions designed for that purpose, there is no guarantee of atomic
read-modify-write, such as in the case of increment or decrement.
So if all you're doing is trying to read/write, and you meet one of the conditions above, then you don't have to do anything (but it means that you also have to place a constraint on the type T
).
If you can't guarantee the constraint on T
, then you'll have to resort to something like the lock
statement to synchronize access (for reads and writes as mentioned before).
If you find that using the lock
statement (really, the Monitor
class) degrades performance, then you can use the SpinLock
structure, as it's meant to help in places where Monitor
is too heavy:
T item;
SpinLock sl = new SpinLock();
public T Item
{
get
{
bool lockTaken = false;
try
{
sl.Enter(ref lockTaken);
return item;
}
finally
{
if (lockTaken) sl.Exit();
}
}
set
{
bool lockTaken = false;
try
{
sl.Enter(ref lockTaken);
item = value;
}
finally
{
if (lockTaken) sl.Exit();
}
}
}
However, be careful, as the performance of SpinLock
can degrade and will be the same as the Monitor
class if the wait is too long; of course, given that you are using simple assignments/reads, it shouldn't take too long (unless you are using a structure which is just massive in size, due to copy semantics).
Of course, you should test this yourself for the situations that you predict that this class will be used and see which approach is best for you (lock
or the SpinLock
structure).