2011-03-08 69 views
0

我试图找出将锁定应用于以下类的正确方法。简而言之,该对象是一个单例,创建时,从给定目录中的xml文件构建可变数目的菜单。现在,只允许读取,因此不发生锁定(MSDN状态读取从字典中是线程安全的)。但是,我还连接了一个文件系统观察器,以便在发生更改时重新构建菜单。有两个字典发生读取,所以我需要一种方法来处理这个问题。我可以使用Lock(this),但有没有更好的方法?所以,我想冻结读取的唯一时间是更新发生的时间(查看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); 
    } 
} 

谢谢。

回答

0

有辛格尔顿实现和优化技术的一个很好的写了here(你确定菜单是单身 - 它是为所有用户相同的菜单?)

既然你想只在锁定优化写操作,你可能也想看看ReaderWriterLockSlim

0

与其锁定,我认为您可能想要使用mutex,updater例程声明它在开始时声明并在完成时释放。

1

你不应该使用lock(this),而应该创建一个lockObject来代替这个对象,并锁定该对象。

+0

是的,但后来我还需要锁定执行读取的两个方法否?这正是我重新构建菜单时只想锁定的位置。锁定(这)将解决这个问题。 – Marco 2011-03-08 14:51:59

+0

@Marco - 您不会锁定* lock()中提到的*实例,您可以锁定实例。巨大差距。 @Felice - 为什么从不“锁定(this)”? – 2011-03-08 14:54:24

+0

当你保护一个静态的时候''lock'应该是静态的,而当你保护一个实例时''lock应该是静态的。 – 2011-03-08 14:55:33

0

它通常建议,以创建用于锁定私有对象:

private object _sync = new Object(); 

通过使用私有对象标识符,上如果类中的代码可以访问它,那么类外的任何代码都不能使用相同的标识符进行锁定并导致死锁。

如果在更改数据的代码中使用锁,则还需要在读取数据的所有代码中使用锁,否则锁就没用了。

请注意,锁并不以任何方式保护数据,它只是一种确保一次只有一个线程进入代码段的方法。

相关问题