我有一个单身类,看起来很像这个,
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; } }
}
然后像这样锁定(Get和Set),
public void Set<T>(T instance) where T : class, new()
{
lock(Locks<T>.Lock)
{
// save to disk
}
}
我错过了一些微不足道的事情吗?有没有更好的方法来实现我的目标?
答案 0 :(得分:5)
每个实例锁定或锁定每种类型?
你这样做的方式(使用静态Locks<T>.Lock
)意味着即使在不同的CfgHandler实例上,每次调用Set<Foo>
都会共享同一个锁。那是你要的吗?我猜你只是锁定每个实例可能会更好 - 它会为你节省Locks<T>
的复杂性。只需声明一个私有实例成员(private object _lock = new object();
)并使用它(lock(this._lock)
)
编辑如果你正在使用CfgHandler
的单例实例并想要锁定每种类型,那么我猜你的方法完全正常。如果您没有使用单个实例,但仍希望锁定每种类型,那么只需确保使用Locks<T>
的实例,而不是将其设置为静态。
答案 1 :(得分:2)
有关详细信息,请在此处查看我的问题:Are static members of generic classes shared between types
您的实施简单但有效,它将阻止对Set<T>(T Instance)
呼叫的并发访问。我唯一的建议是,如果要对此API进行多次并发调用,则应限制锁定持续时间。例如,您可以完成所有工作,但只能锁定对writer.write(instance)
调用的调用,这是您在调用中看到的唯一非线程安全工作。
顺便说一下,您可以在Get Call上改进您的代码,请在Is there a way to check if a file is in use?查看我的答案,了解您对现有文件的检查。