lock()函数在c#中是如何工作的?

lock()函数在c#中是如何工作的?,c#,asp.net,locking,deadlock,C#,Asp.net,Locking,Deadlock,我有一些c#代码,看起来像这样: if (cache[filename] != null) { return (AppSettings)cache[filename]; } lock (thisLock) { using (StreamReader sr = new StreamReader(filename)) { instance = (AppSettings)serial.Deserialize(sr); cache.Insert(

我有一些c#代码,看起来像这样:

if (cache[filename] != null) {
    return (AppSettings)cache[filename];
}

lock (thisLock)
{
    using (StreamReader sr = new StreamReader(filename))
    {
        instance = (AppSettings)serial.Deserialize(sr);
        cache.Insert(filename, instance, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration);
    }

}

return (AppSettings)cache[filename];
AppSettings result = null;

lock (thisLock)
{
    if (cache[filename] != null) {
        result = (AppSettings)cache[filename];
    }
    else
    {
        using (StreamReader sr = new StreamReader(filename))
        {
            instance = (AppSettings)serial.Deserialize(sr);
            cache.Insert(filename, instance, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration);
        }

        result = (AppSettings)cache[filename];
    }
}

return result;
因此,我对锁的理解是,一旦它被“解锁”,那么代码块将被执行。因此,对于上面的代码,我假设需要在锁代码块中进行另一次检查,以查看对象是否已经创建


另外,如何检查死锁?

当另一个线程正在处理时,
lock
指令将阻止任何其他线程进入。您可以使用它来保护非线程安全的受保护资源

在您的例子中,字典
缓存
是您想要保护的,因为如果多个线程在其中添加、更改和删除元素,您的程序几乎肯定会崩溃

要保护
缓存
,需要将整个操作包装在
语句中,如下所示:

if (cache[filename] != null) {
    return (AppSettings)cache[filename];
}

lock (thisLock)
{
    using (StreamReader sr = new StreamReader(filename))
    {
        instance = (AppSettings)serial.Deserialize(sr);
        cache.Insert(filename, instance, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration);
    }

}

return (AppSettings)cache[filename];
AppSettings result = null;

lock (thisLock)
{
    if (cache[filename] != null) {
        result = (AppSettings)cache[filename];
    }
    else
    {
        using (StreamReader sr = new StreamReader(filename))
        {
            instance = (AppSettings)serial.Deserialize(sr);
            cache.Insert(filename, instance, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration);
        }

        result = (AppSettings)cache[filename];
    }
}

return result;
因此,对于上面的代码,我假设需要在锁代码块中进行另一次检查,以查看对象是否已经创建

对。如果两个线程都检查并发现缓存项丢失,那么您只希望其中一个线程实际执行在缓存中创建该项的昂贵工作,而不是两个线程,因此您需要在锁内部再次应用相同的检查。这就是著名的“双重检查锁定”模式

另外,我如何检查死锁


我看到您的代码具有死锁的唯一方式是,如果其他线程持有要访问的文件上的锁,并且它正在等待
块中的某个线程执行它想要执行的其他操作。这将是一个僵局。如果您确保此代码是唯一可以访问该文件的代码,或者任何访问此文件的内容都不会依赖于此线程,那么(给定您显示的代码)您会没事的。

可能重复请注意,您的代码仍然完全不安全。@SLaks
缓存
对象是专门设计用于同时从多个线程操作的,因此一个线程可能正在读取一个值,而另一个线程正在写入该值这一事实不是问题(只要您不关心这些概念性操作发生的顺序)。在这里使用
锁的唯一原因是避免使用多个线程读取文件(此代码正确执行),并且可能还避免在缓存未命中时多次读取文件(这一部分它没有做到,但可以很容易地修改来做到)。根据其文档,
缓存
对象是专门设计来同时从多个线程进行操作的,因此OP的代码实际上是完全安全的。在这种情况下,我同意,没有必要保护它。