I want to create a class which stores DataTables, this will prevent my application to import a list of details each time I want to retrieve it. Therefore this should be done
If you are on .net 4 you could use ThreadLocal wrappers on your datatables
It appears as though all you want to do is load it once and keep a reference to it. All you need to guard is initialising the variable if it's null. Null checking, locking and null checking again is called Double Check Locking and will work well for you. It's best practice to provide a separate locking object, so you have good control over granularity of locks.
Note this doesn't stop people from mutating the value inside the DataTable
it only stops people from trying to initialise the static member at the same time.
private static readonly object UnitTableLock = new object();
private static DataTable unitTable;
private static bool _ready = false;
public static DataTable GetUnitList()
{
if (!_ready)
{
lock (UnitTableLock)
{
if (!_ready)
{
unitTable = new DataTable; //... etc
System.Threading.Thread.MemoryBarrier();
_ready = true;
}
}
}
return unitTable;
}
Only read from the result of GetUnitList
never write to it.
Amended with reference to http://en.wikipedia.org/wiki/Double-checked_locking
If the DataTables are read-only then you should lock them when you populate them and if they never change then they will be thread safe.
public class BusinessLayerHandler
{
public static DataTable unitTable;
public static DataTable currencyTable;
private static readonly object unitTableLock = new object();
private static readonly object currencyTableLock = new object();
public static DataTable GetUnitList()
{
//import lists each time the application is run
lock(unitTableLock)
{
if (unitTable == null)
{
unitTable = DatabaseHandler.GetUnitList();
}
}
return unitTable;
}
public static DataTable GetCurrencyList()
{
//import lists each time the application is run
lock(currencyTableLock)
{
if (currencyTable == null)
{
currencyTable = DatabaseHandler.GetCurrencyList();
}
}
return currencyTable;
}
}
If you need really high performance on this lookup you can use the ReaderWriterLockSlim class instead of a full lock everytime to limit the number of waits that will happen in the application.
Check out http://kenegozi.com/blog/2010/08/15/readerwriterlockslim-vs-lock for a short article on the differences between lock and ReaderWriterLockSlim
EDIT: (Answer to comments below)
The unitTableLock object is used like a handle for the Monitor class in to synchronize against.
For a full overview of Theading and synchronization in the .NET framework I would point you over to this very extensive tutorial http://www.albahari.com/threading/
I thought it would be worth adding that Double Check Locking has since been implemented in .net framework 4.0 in a class named Lazy. So if you would like your class to include the locking by default then you can use it like this:
public class MySingleton
{
private static readonly Lazy<MySingleton> _mySingleton = new Lazy<MySingleton>(() => new MySingleton());
private MySingleton() { }
public static MySingleton Instance
{
get
{
return _mySingleton.Value;
}
}
}
Static variables aren't thread safe per-se. You should design with thread safety in mind.
There's a good link to get you started: http://en.csharp-online.net/Singleton_design_pattern%3A_Thread-safe_Singleton
Apart from this, I would strongly recommend you to use a more modern approach than the legacy DataTable. Check out the Entity Framework or NHibernate. Implementing them in your datalayer will allow you to hide database details from the rest of the software and let it work on a higher level abstraction (POCO objects).
They are not thread safe. You should think about making your logic thread safe by your self, for example, by using lock operator.