Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/268.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在哪里以及如何应用锁_C#_Multithreading_Concurrency - Fatal编程技术网

C# 在哪里以及如何应用锁

C# 在哪里以及如何应用锁,c#,multithreading,concurrency,C#,Multithreading,Concurrency,我试图找出将锁定应用于以下类的正确方法。简而言之,该对象是一个单例对象,在创建时,会根据给定目录中的xml文件构建数量可变的菜单。现在,只允许读取,因此不会发生锁定(MSDN状态读取在字典中是线程安全的)。但是,我还安装了一个文件系统监视程序,以便在发生更改时重新构建菜单。有两个字典可以阅读,所以我需要一种方法来处理这个问题。我可以用锁(这个),但有更好的方法吗?因此,我唯一想冻结读取的时间是在更新发生时(查看ctor) 下面是一个视觉课程: public class XmlMenuProvid

我试图找出将锁定应用于以下类的正确方法。简而言之,该对象是一个单例对象,在创建时,会根据给定目录中的xml文件构建数量可变的菜单。现在,只允许读取,因此不会发生锁定(MSDN状态读取在字典中是线程安全的)。但是,我还安装了一个文件系统监视程序,以便在发生更改时重新构建菜单。有两个字典可以阅读,所以我需要一种方法来处理这个问题。我可以用锁(这个),但有更好的方法吗?因此,我唯一想冻结读取的时间是在更新发生时(查看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);
    }
}
公共类XmlMenuProvider:IMenuProvider{
私有只读的INavigationService导航;
专用只读词典菜单;
私有只读字典菜单查找;
专用只读文件系统监视器;
公共XmlMenuProvider(字符串折叠路径,INavigationService导航)
{
这个.导航=导航;
this.menusLookup=新字典();
this.menus=LoadFromSourceDirectory(folderPath);
this.monitor.Changed+=(o,e)=>{
//TODO-添加锁定
};
}
公共IEnumerable GetMenuItems(字符串名称){
返回菜单[名称];
}
公共菜单项FindItemByName(字符串菜单,字符串名称){
返回菜单查找[菜单][名称];
}
私有字典LoadFromSourceDirectory(字符串folderPath){
var菜单=新字典();
foreach(目录.GetFiles(folderPath,*.xml)中的var文件){
var root=XDocument.Load(file.Elements().First();
var name=root.Attribute(“name”).Value;
var lookup=newdictionary();
menusLookup.Add(名称、查找);
添加(名称,BuildMenuHiearchyFromElement(根,查找,空));
}
返回菜单;
}
私有IEnumerable BuildMenuHiearchyFromElement(XElement元素、字典查找、MenuItem父级){
返回元素。元素(“项”)
.选择(e=>{
var mi=CreateMenuItemFromElement(e,lookup,parent);
lookup.Add(mi.Name,mi);
返回mi;
}
).ToList();
}
私有MenuItem CreateMnuItemFromElement(XElement元素、字典查找、MenuItem父级){
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){
角色=新字符串[]{};
}
var attrClick=element.Attribute(“IsClickable”);
如果(单击!=null){
isClickable=bool.Parse(attrClick.Value);
}
var navigateUrl=string.Empty;
如果(可点击){
navigateUrl=navigation.FetchDestination(名称);
}
返回新的MenuItem(名称、显示、导航、可点击、角色、x=>BuildMenuHiearchyFromElement(元素、查找、x)、父级);
}
}

谢谢。

我认为您可能希望使用更新程序例程在开始时声明的锁,并在完成时释放的锁。

您不应该使用锁(这个),而应该创建一个锁对象(类中的私有对象的距离)并锁定该对象,而不是此对象。

单例实现和优化有一个很好的总结(您确定菜单是单例菜单吗?所有用户的菜单都是相同的吗?)


由于您希望仅对写入操作进行锁定优化,您可能还希望查看

通常建议创建用于锁定的私有对象:

private object _sync = new Object();
通过使用私有对象作为标识符,只有类中的代码可以访问它,因此类外的任何代码都不会使用相同的标识符锁定并导致死锁

如果在更改数据的代码中使用锁,则还需要在读取数据的所有代码中使用锁,否则该锁将无效


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

是的,但我还需要锁定执行读取否的两个方法??这正是我在重新构建菜单时只想锁定的地方。Lock(这个)可以解决这个问题。@Marco-如果不锁定
Lock()
中提到的实例,则锁定该实例。差别很大@Felice-为什么从不
lock(this)
lock
在保护静态时应该在静态上,在保护实例时应该在实例上。@Michael锁定这可能会导致死锁,因为任何人都可以锁定它,即使是在外部。