Где и как применить блокировку - PullRequest
0 голосов
/ 08 марта 2011

Я пытаюсь найти правильный способ применения блокировки к следующему классу.В двух словах, объект является одноэлементным, и при его создании строится переменное число меню из XML-файлов в данном каталоге.В настоящее время разрешено только чтение, поэтому блокировка не происходит (состояния MSDN считывают потоки из словаря).Но у меня также есть средство наблюдения за файловой системой, так что я могу пересоздавать меню, когда происходят изменения.Есть два словаря, в которых происходит чтение, и поэтому мне нужен способ справиться с этим.Я мог бы использовать Lock (это), но есть ли лучший способ?Итак, единственный раз, когда я хочу заморозить чтения, это когда происходит обновление (смотрите в ctor).

Вот класс для визуала:

public class XmlMenuProvider : IMenuProvider {
    private readonly INavigationService navigation;
    private readonly Dictionary<string, IEnumerable<MenuItem>> menus;
    private readonly Dictionary<string, Dictionary<string, MenuItem>> menusLookup;
    private readonly FileSystemWatcher monitor;

    public XmlMenuProvider(string folderPath, INavigationService navigation)
    {
        this.navigation = navigation;
        this.menusLookup = new Dictionary<string, Dictionary<string, MenuItem>>();
        this.menus = LoadFromSourceDirectory(folderPath);
        this.monitor.Changed += (o, e) => {
                // TODO - Add Locking
            };
    }

    public IEnumerable<MenuItem> GetMenuItems(string name) {
        return menus[name];
    }

    public MenuItem FindItemByName(string menu, string name) {
        return menusLookup[menu][name];
    }

    private Dictionary<string, IEnumerable<MenuItem>> LoadFromSourceDirectory(string folderPath) {
        var menus = new Dictionary<string, IEnumerable<MenuItem>>();
        foreach (var file in Directory.GetFiles(folderPath, "*.xml")) {
            var root = XDocument.Load(file).Elements().First();
            var name = root.Attribute("name").Value;

            var lookup = new Dictionary<string, MenuItem>();
            menusLookup.Add(name, lookup);
            menus.Add(name, BuildMenuHiearchyFromElement(root, lookup, null));
        }
        return menus;
    }

    private IEnumerable<MenuItem> BuildMenuHiearchyFromElement(XElement element, Dictionary<string, MenuItem> lookup, MenuItem parent) {
        return element.Elements("Item")
                      .Select(e => {
                          var mi = CreateMenuItemFromElement(e, lookup, parent);
                          lookup.Add(mi.Name, mi);
                          return mi;
                      }
                ).ToList();
    }

    private MenuItem CreateMenuItemFromElement(XElement element, Dictionary<string, MenuItem> lookup, MenuItem parent) {
        var name = element.Attribute("Name").Value;
        var display = element.Attribute("DisplayName").Value;
        var isClickable = true;

        var roles = element.Attribute("Roles").Value.Split(',');
        if (roles.Length == 1 && roles.First() == string.Empty) {
            roles = new string[] { };
        }
        var attrClick = element.Attribute("IsClickable");
        if (attrClick != null) {
            isClickable = bool.Parse(attrClick.Value);
        }
        var navigateUrl = string.Empty;
        if (isClickable) {
            navigateUrl = navigation.FetchDestination(name);
        }

        return new MenuItem(name, display, navigateUrl, isClickable, roles, x => BuildMenuHiearchyFromElement(element, lookup, x), parent);
    }
}

Спасибо.*

Ответы [ 4 ]

1 голос
/ 08 марта 2011

Вы никогда не должны использовать lock (this), но вместо этого создайте lockObject (экземпляр объекта private в классе) и заблокируйте этот объект вместо этого.

0 голосов
/ 08 марта 2011

Обычно рекомендуется создать закрытый объект, который вы используете для блокировки:

private object _sync = new Object();

Используя личный объект в качестве идентификатора, только код в классе может получить к нему доступ, поэтому нет риска, чтолюбой код вне класса может блокироваться с использованием того же идентификатора и вызывать взаимоблокировку.

Если вы используете блокировку в коде, который изменяет данные, вам также необходимо использовать блокировку во всем коде, который читает данные, в противном случаеблокировка бесполезна.

Обратите внимание, что блокировка никак не защищает данные, это всего лишь способ убедиться, что только один поток за раз входит в раздел кода.

0 голосов
/ 08 марта 2011

Существует хорошее описание реализаций и оптимизаций Singleton здесь (вы уверены, что меню одноэлементное - это одно и то же меню для всех пользователей?)

Поскольку вы хотите оптимизировать с блокировкой только на записи, вы также можете посмотреть на ReaderWriterLockSlim

0 голосов
/ 08 марта 2011

Вместо блокировки, я думаю, вы можете использовать мьютекс , который программа обновления запрашивает, когда она начинается, и освобождает, когда она закончена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...