仅在修改vs整个方法时锁定

时间:2010-12-14 16:34:16

标签: c# multithreading

什么时候应该使用锁?仅在修改数据或访问数据时?

public class Test {
    static Dictionary<string, object> someList = new Dictionary<string, object>();

    static object syncLock = new object();

    public static object GetValue(string name) {
        if (someList.ContainsKey(name)) {
            return someList[name];
        } else {
            lock(syncLock) {
                object someValue = GetValueFromSomeWhere(name);
                someList.Add(name, someValue);
            }
        }
    }
}

整个区块周围是否存在锁定或者是否可以将其添加到实际修改中?我的理解是,仍然可能存在一些竞争条件,其中一个呼叫可能没有找到并开始添加它,而另一个呼叫可能也会遇到相同的情况 - 但我不确定。锁定仍然令人困惑。我没有遇到上述类似代码的任何问题,但到目前为止我可能很幸运。上面的任何帮助都会被评估,以及任何有关如何/何时锁定对象的好资源。

4 个答案:

答案 0 :(得分:8)

您也必须在读取时锁定,或者您可以获得不可靠的数据,或者甚至是并发修改在物理上更改目标数据结构时的异常。

在上面的例子中,您需要确保多个线程不会同时尝试添加值,因此在检查它是否已存在时至少需要一个读锁定。否则多个线程可能决定添加,找不到该值(因为此检查未锁定),然后所有尝试依次添加(获取锁定后)

如果您有多次读取且只有少量写入,则可以使用ReaderWriterLockSlim。在上面的代码中,一旦您决定需要添加它,您将获得读锁以进行检查并升级到写锁。在大多数情况下,只需要一个读锁(允许你的读者线程仍然并行运行)。

可用.Net 4锁定原语here的摘要。在你深入研究多线程代码之前,你肯定应该理解这一点。选择正确的锁定机制可以产生巨大的性能差异。

你是幸运的,到目前为止你很幸运 - 这是并发错误的常见特征。如果没有针对性的负载测试,它们通常难以重现,这意味着正确的设计(当然,详尽的测试)对于避免令人尴尬和混乱的生产错误至关重要。

答案 1 :(得分:1)

在检查是否存在name之前锁定整个块。否则,理论上,另一个线程可以在检查和添加它的代码之间添加它。

实际上在执行添加时锁定实际上根本没有做任何事情。所做的就是阻止另一个线程同时添加内容。但是因为其他线程已经决定它会进行添加,所以只要锁定被释放就会尝试执行它。

答案 2 :(得分:1)

如果多个线程只能访问资源 ,则不需要任何锁定。

如果多个线程可以访问资源并且可以修改,则需要同步所有访问/修改。在您的示例中,如果GetValueFromSomeWhere需要很长时间才能返回,则可能会在name中使用相同的值进行第二次调用,但该值尚未存储在{{1}中}}。

答案 3 :(得分:0)

ReaderWriterLock或精简版,如果你在4.0以下。

您将获取读取器锁定读取(将允许并发读取)并在写入某些内容时将锁定升级到写入器锁定(此时将只允许一次写入并将阻止所有读取,直到完成,以及并发写线程。)

确保使用模式释放锁定以避免死锁:

            void Write(object[] args) 
            {


                   this.ReaderWriterLock.AquireWriteLock(TimeOut.Infinite);

                    try 
                    {
                      this.myData.Write(args);

                    }
                    catch(Exception ex) 
                    {

                    }
                    finally 
                    {

                        this.ReaderWriterLock.RelaseWriterLock();
                    }

            }
相关问题