多线程,通用锁
本文关键字:多线程 | 更新日期: 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 调用上改进您的代码,请在此处查看我的答案 有没有办法检查文件是否正在使用中? 关于您对文件存在的检查。