C#锁定机制 - 只写锁定

时间:2011-08-14 19:23:54

标签: c# locking mutex race-condition

继续讨论关于C#和.NET中的锁的最新思考,

考虑以下情况:

我有一个类,其中包含一个特定的集合(对于此示例,我使用了Dictionary<string, int>),它使用特定的方法每隔几分钟从数据源更新一次,您可以在下面看到它:

    DataTable dataTable = dbClient.ExecuteDataSet(i_Query).GetFirstTable();

    lock (r_MappingLock)
    {
        i_MapObj.Clear();

        foreach (DataRow currRow in dataTable.Rows)
        {
            i_MapObj.Add(Convert.ToString(currRow[i_Column1]), Convert.ToInt32[i_Column2]));
        }
    }

r_MappingLock是一个专门用于锁定关键部分的对象,用于刷新字典的内容。

i_MapObj是字典对象

i_Column1和i_Column2是数据表的列名,其中包含映射所需的数据。

现在,我还有一个类方法,它接收一个字符串并根据提到的字典返回正确的映射int。

我希望这个方法等到刷新方法完成它的执行,所以乍看之下会考虑以下实现:

    lock (r_MappingLock)
    {
        int? retVal = null;

        if (i_MapObj.ContainsKey(i_Key))
        {
            retVal = i_MapObj[i_Key];
        }

        return retVal;
    }

这将防止在更新字典时出现意外行为和返回值,但会出现另一个问题: 由于执行上述方法的每个线程都试图声明锁定,这意味着如果多个线程同时尝试执行此方法,则每个线程都必须等到上一个线程完成执行该方法并尝试声明锁定,这显然是一种不良行为,因为上述方法仅用于读取目的。

我正在考虑在类中添加一个布尔成员,该类将被设置为true或false,字典是否正在更新,并在“只读”方法中检查它,但这会产生其他基于竞争条件的问题...

任何想法如何优雅地解决这个问题?

再次感谢,

米奇

5 个答案:

答案 0 :(得分:8)

查看内置的ReaderWriterLock

答案 1 :(得分:4)

我只想切换到使用ConcurrentDictionary来完全避免这种情况 - 手动锁定容易出错。另外,我可以从"C#: The Curious ConcurrentDictionary"收集,ConcurrentDictionary已经过读取优化。

答案 2 :(得分:2)

Albin在ReaderWriterLock正确指出。我将添加一个更好的一个:杰弗里里希特ReaderWriterGate。享受!

答案 3 :(得分:1)

您可以考虑在更新时创建新字典,而不是锁定。这样,您将始终获得一致的结果,但更新期间的读取将返回以前的数据:

private volatile Dictionary<string, int> i_MapObj = new Dictionary<string, int>();

private void Update()
{
    DataTable dataTable = dbClient.ExecuteDataSet(i_Query).GetFirstTable();

    var newData = new Dictionary<string, int>();
    foreach (DataRow currRow in dataTable.Rows)
    {
        newData.Add(Convert.ToString(currRow[i_Column1]), Convert.ToInt32[i_Column2]));
    }

    // Start using new data - reference assignments are atomic
    i_MapObj = newData;
}

private int? GetValue(string key)
{
    int value;
    if (i_MapObj.TryGetValue(key, out value))
        return value;

    return null;
}

答案 4 :(得分:0)

在C#4.0中,ReaderWriterLockSlim类速度更快! 几乎和lock()一样快。

保持策略禁止递归(LockRecursionPolicy :: NoRecursion)以保持高性能。

Look at this page for more info.