Let\'s take Wes Dyer\'s approach to function memoization as the starting point:
public static Func Memoize(this Func f)
{
You don't want to calculate the same value twice and you want many threads to be able to calculate values and or retrieve values concurrently. To do this you will need to use some sort of condition variable and fine grained locking system.
Heres the idea. when no value is present you put a value into the sync map and then any thread who needs that value will wait for it otherwise you will just grab the current value. this way locking of the map is minimized to querying for values and returning values.
public static Func Memoize(this Func f)
{
var map = new Dictionary();
var mapSync = new Dictionary();
return a =>
{
R value;
object sync = null;
bool calc = false;
bool wait = false;
lock (map)
{
if (!map.TryGetValue(a, out value))
{
//its not in the map
if (!mapSync.TryGetValue(a, out sync))
{
//not currently being created
sync = new object();
mapSync[a] = sync;
calc = true;
}
else
{
calc = false;
wait = true;
}
}
}
if(calc)
{
lock (sync)
{
value = f(a);
lock (map)
{
map.Add(a, value);
mapSync.Remove(a);
}
Monitor.PulseAll(sync);
return value;
}
}
else if (wait)
{
lock (sync)
{
while (!map.TryGetValue(a, out value))
{
Monitor.Wait(sync);
}
return value;
}
}
lock (map)
{
return map[a];
}
};
}
This is just a quick first try but i think it demonstrates the technique. Here you are trading additional memory for speed.