多线程,通用锁

时间:2012-04-26 13:25:00

标签: c# multithreading locking

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

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
    }
}

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

2 个答案:

答案 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?查看我的答案,了解您对现有文件的检查。