2011-03-08 3 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 (당신은 메뉴가 싱글인지 확인 - 그것은 모든 사용자에 대해 동일한 메뉴입니다?)

만에 잠금으로 최적화 할 때문에 에, 식별자로 개인 개체를 사용하여

private object _sync = new Object(); 

: 쓰기 작업, 당신은 또한 ReaderWriterLockSlim

0

자물쇠보다 오히려 업데이트 루틴이 시작될 때 클레임이 끝나고 해제 될 때 mutex을 사용하려고한다고 생각합니다.

1

결코 lock (this)을 사용하지 말고 대신 lockObject (클래스에 개인 객체의 istance)를 만들고이 객체 대신에 잠글 수 있습니다.

+0

네, 그렇지만 읽기를 수행하는 두 가지 방법을 잠글 필요가 없습니까 ?? 바로 그 부분은 메뉴를 다시 작성할 때 잠글 때만 필요합니다. Lock (이)이 문제를 해결할 것입니다. – Marco

+0

@Marco -'lock()'에 언급 된 * 인스턴스를 잠그지 않고 인스턴스에 고정시킵니다. 큰 차이. @ Felice - 왜 결코 '잠 가야합니까?' –

+0

정적을 보호 할 때는'lock'을 정적으로, 인스턴스를 보호 할 때는 인스턴스에'lock'을 설정해야합니다. –

0

보고 할 수 있습니다 일반적으로 당신이 잠금에 사용하는 개인 객체를 생성하는 것이 좋습니다 클래스의 코드가 액세스 할 수 있으므로 클래스 외부의 모든 코드가 동일한 식별자를 사용하여 잠기고 교착 상태가 발생할 위험이 없습니다.

데이터를 변경하는 코드에서 lock을 사용하는 경우 데이터를 읽는 모든 코드에서 잠금을 사용해야합니다. 그렇지 않으면 잠금이 유효하지 않습니다.

잠금은 어떤 방식 으로든 데이터를 보호하지는 않으며, 한 번에 하나의 스레드 만 코드 섹션에 들어가는 것을 확인할 수있는 유일한 방법입니다.