Состояние гонки в Rhino DSL?
В моем текущем проекте я работаю с Boo/ Rhino DSL (кстати, это здорово).
При копании в коде я наткнулся на следующий фрагмент кода:
engine.Cache.WriteLock( () =>
{
engine.Storage.NotifyOnChange(urls, delegate(string invalidatedUrl)
{
engine.Cache.Remove(invalidatedUrl);
if (!standAloneCompilation.Contains(invalidatedUrl))
standAloneCompilation.Add(invalidatedUrl);
});
});
намерение здесь довольно ясно: engine.Cache
должен быть защищен от состояния гонки, когда URL удален из него. Проблема, которую я вижу здесь, состоит в том, что действительно защищенным является призыв к Storage.NotifyOnChange
- не Cache.Remove
,
И все NotifyOnChange
do принимает предоставленный делегат и присоединяет его в качестве обработчика события к "FileWatcher", который он создает. Таким образом, вместо защиты Cache.Remove
блокировка записи защищает создание FileWatcher и оставляет Cache.Remove
незащищенный.
Я испытываю большое уважение к Бу и Носорогу, и это заставляет меня задуматься - что-то здесь не так? или блокировка записи должна быть действительно перемещена внутри делегата?
Вот код NotifyOnChange, если вам интересно:
public virtual void NotifyOnChange(IEnumerable<string> urls, Action<string> action)
{
lock (pathToFileWatchers)
{
string[] commonPaths = GatherCommonPaths(urls);
foreach (string path in commonPaths)
{
FileSystemWatcher watcher;
if(pathToFileWatchers.TryGetValue(path, out watcher)==false)
{
pathToFileWatchers[path] = watcher = new FileSystemWatcher(path, FileNameFormat);
watcher.EnableRaisingEvents = true;
}
watcher.Changed += delegate(object sender, FileSystemEventArgs e)
{
action(e.FullPath);
};
}
}
}