多线程,通用锁

本文关键字:多线程 | 更新日期: 2023-09-27 18:32:24

我有一个单例类,看起来很像这样,

public class CfgHandler
{
    private static readonly string ConfigDir = "Config";
    public T Get<T>() where T : class, new()
    {
        string cfgFile = Path.Combine(ConfigDir, typeof(T).FullName + ".json");
        if (File.Exists(cfgFile))
        {
            var reader = new JsonReader();
            return reader.Read<T>(File.ReadAllText(cfgFile));
        }
        return null;
    }
    public void Set<T>(T instance) where T : class, new()
    {
        string cfgFile = Path.Combine(ConfigDir, typeof(T).FullName + ".json");
        var writer = new JsonWriter();
        string json = writer.Write(instance);
        File.WriteAllText(cfgFile, json);
    }
}

该类用于多线程环境,我想添加锁。但不是整个类的一个锁,因为我不希望cfg.Set<Foo>();cfg.Set<Bar>()之间出现竞争条件,因为它们处理不同的数据。

我考虑过将以下类添加到CfgHandler

private static class Locks<T>
{
    private static object _lock = new object();
    public static object Lock { get { return _lock; } }
}

然后像这样锁定(对于获取和设置),

public void Set<T>(T instance) where T : class, new()
{
    lock(Locks<T>.Lock)
    {
        // save to disk
    }
}

我错过了一些微不足道的东西吗?有没有更好的方法来实现我的目标?

多线程,通用锁

按实例锁定还是按类型锁定?

您执行此操作的方式(使用静态Locks<T>.Lock)意味着每次调用Set<Foo>,即使在不同的 CfgHandler 实例上,也将共享相同的锁。这就是你想要的吗?我猜您可能最好只锁定每个实例 - 这将为您节省Locks<T>的复杂性。只需声明一个私有实例成员 ( private object _lock = new object(); ) 并使用它 ( lock(this._lock)

编辑 如果您使用的是CfgHandler的单例实例并希望按类型锁定,那么我想您的方法完全没问题。如果您没有使用单个实例,但仍希望按类型锁定,则只需确保使用 Locks<T> 实例而不是将其设置为静态。

有关更多详细信息,请参阅我的问题: 泛型类的静态成员是否在类型之间共享

您拥有的实现简单但有效,它将阻止并发访问正确Set<T>(T Instance)调用。 我唯一的建议是,如果您要对此 API 进行多次并发调用,则应限制锁定持续时间。 例如,您可以完成所有工作,但仅将调用锁定到writer.write(instance)调用,这是您在调用中似乎正在执行的唯一非线程安全工作。

另外,您有可能在 Get 调用上改进您的代码,请在此处查看我的答案 有没有办法检查文件是否正在使用中? 关于您对文件存在的检查。