I want to realize an object cache which holds objects loaded from database, file or other slow access source, to make them available quickly with high performance. There will be a lot of accesses to get these objects from the dictionary!
It's not supposed to be Singleton/Static; multiple different object holders are possible, with multiple threads running on each.
Access is usually read-only, the objects themselves (in the dictionary) shall not be changed after being created.
For some special Admin functions, a Reload method exists, where thread safety can be ignored (not to be used by the main, multi-threaded program).
If I am right, the .NET Dictionary is thread-safe, as long as it is used only in read access, thus not requiring locks in reading methods. The dictionary will not be changed after being assigned to the _progObjects
variable (do I need to make it volatile?). But time consuming volatile (alternatively Interlocked) access on the _areProgObjectsInitialized
variable seems to be necessary, to make first accesses (with initialization) thread-safe.
Is the following a good and performant solution, can it still be improved, or are there safety risks?
/// <summary>
/// Not Singleton, but each instance multi-threaded!
/// Holds objects loaded from an external source (database, file, whatever...)
/// </summary>
public class ProgObjectsThreadSafeRead : IProgObjectsThreadSafeRead
{
private IDictionary<ObjectKey, object> _progObjects = null;
private object _progObjectsSyncObj = new object();
private volatile bool _areProgObjectsInitialized = false;
private void InitializeProgObjectsIfNeeded()
{
if (!_areProgObjectsInitialized)
{
lock(_progObjectsSyncObj)
{
if (!_areProgObjectsInitialized)
{
IDictionary<ObjectKey, object> localProgObj = LoadProgObjects();
// do something more
_progObjects = localProgObj;
_areProgObjectsInitialized = true;
}
}
}
}
public object GetProgObject(ObjectKey key)
{
InitializeProgObjectsIfNeeded();
return _progObjects[key];
}
/// <summary>
/// Not thread safe, don't use in multi-thread environments!
/// Specific editing tools only! Not in interface.
/// </summary>
public void ReloadProgObjects()
{
lock (_progObjectsSyncObj)
{
_areProgObjectsInitialized = false;
InitializeProgObjectsIfNeeded();
}
}
// others removed
}