I have some read-only data that I want to initialise and then re-initialise periodically in a thread-safe manner. For initialisation I've pulled in Joe Duffy's LazyInit and LazyInitOnceOnly structs as detailed in his blog, which use the Double-Checked locking pattern. So my current implementation of the getter simply wraps around his LazyInitOnceOnly.Value
property, with added space given to a time out check:
So the code is as follows:
public class MyData {
public DateTime TimeStamp { get; set; }
//actual shared data ommitted
public MyData() { TimeStamp = DateTime.Now; }
}
public SharedDataContainer
{
//data to be initialised thread-safe, and shared.
//assume delegate passed on construction simply 'new's the object,
private LazyInitOnceOnly<MyData> _sharedDataInit;
//receives the result from the _sharedDataInit.Value property
private MyData _sharedData;
//time-out and reinitialise after 24 hours
private TimeSpan _timeOut = new TimeSpan(24,0,0);
public MyData SharedData
{
get{
//slight adaptation of the use of the LazyInitOnceOnly struct -
//because we want to replace _sharedData later after an expiry time out.
if(_sharedData == null)
_sharedData = _sharedDataInit.Value;
//need best ideas for this bit:
if((DateTime.Now - _sharedData.TimeStamp) > _timeOut)
{
ReInitialise();
}
return _sharedData;
}
}
}
When the data is identified as out of date, the old data should be returned, but the new data should be prepared on a separate thread and swapped in when ready - so as not to block the caller. All subsequent reads from the data should return the old value until it's updated.
So I considered queueing new thread like this in the ReInitialise()
method:
() => {
//assume constructor pulls in all the data and sets timestamp
_sharedData = new MyData();
}
The _sharedData overwrite in the thread will occur atomically, so that's fine. But with this code, until the rebuild is complete, all subsequent reads will try and trigger a threaded rebuild - since they are reading the old _sharedData's TimeStamp property.
What's the best way to ensure that only one rebuild is triggered?