Состояние гонки в Rhino DSL? - PullRequest
2 голосов
/ 19 ноября 2010

В моем текущем проекте я работаю с 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 делает, это берет предоставленный делегат и присоединяет его в качестве обработчика событий к «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);
                };
            }
        }
    }
...