2012-07-16 49 views
0

我知道这个话题已经被打砸了,因为我已经阅读了SO和其他地方的帖子的帖子,但我还没有找到一个明确的答案,所以我道歉,如果你是被这种看似冗余的感觉所感染。一次写多次锁

我有一种情况,有一次写入,读取百万资源。该资源的创建非常昂贵,并且写入锁的争用也可能非常高。此外,我无法预测它将运行在哪个处理器上,所以我不知道内存模型将在下面。我正在编译.NET 3.5,.NET 4.0和Mono 2.10中构建的程序集的3个版本。

由于对资源的高度争用,我需要尽可能提高效率,并且希望至少在读取时使用无锁模式。我理解用于创建资源的双重锁定检查模式,但是由于_resource访问内存障碍之外,它是否工作(在所有处理器上)存在分歧。我需要在_resource字段上使用volatile吗? ReaderWriterLockSlim更适合这种情况吗?我应该问什么其他问题?

if(_resource == null) 
{ 
    lock(_locker) 
    { 
     if(_resource == null) 
     { 
      //create resource here... 
     }  
    } 
} 

此外,还会有许多这样的:

if(_resource == null) 
{ 
    return _resourceDefault; 
} 

return _resource.GetSomething(); 
+0

为什么还要在这里锁定? – leppie 2012-07-16 12:11:59

+0

由于创建资源非常昂贵,我不能让它多做一次。它包括跟踪连接的服务器的远程通信。 – 2012-07-16 12:41:17

+0

好吧,早在线程开始阅读之前就已经完成了。不需要锁。这一切都太模糊,不能给出具体的建议。 – 2012-07-16 13:58:58

回答

1

决定推动我一个答案评论。

在创建单例读取时,http://msdn.microsoft.com/en-us/library/ff650316.aspx。它交叉链接一篇文章,深入解释与双重检查锁定有关的一些问题。为了完全安全,微软的文章推荐使用volatile。

如果你真的只想创建一个singleton(一次性事物...没有锁定促销或任何必要的东西,你真的只需要保护创建资源)。一旦创建资源,您将不会触摸该锁。

我会设计访问你的单例总是经历一个静态属性/方法,所以你可以随时做双重检查。

关于资源默认情况下,我不认为我足够了解您的情况以正确回答。您是否期望主资源永远为空(创建之前除外)?根据您的使用情况,您可能可以使用非阻塞的Moniter.TryEnter,并返回一个值,让您知道是否收到该锁。如果您无法立即获取锁创建单例,则可以返回默认值。

+0

是的,有时我们可以返回一些结果而不需要资源。但是,如果资源在那里,我们将使用它,否则,我们只会返回一些默认值。 – 2012-07-16 18:17:30

+0

我已经阅读了你链接的论文,但是有一些矛盾的信息涉及什么时候应该使用volatile,何时不应该等等......通常,在基于x86或x64的机器上,你不需要它。但是,我无法确定我将在什么时候运行硬件,并且需要确保在阅读时使用获取栅栏。我想我可以发出一个Thread.MemoryBarrier(),但是这开始使事情难以阅读。无论如何,感谢您的努力,我会等待,看看是否有其他人接受之前输入。 – 2012-07-16 18:19:51

+0

似乎volatile在.NET 2.0或更高版本中不是必需的,但由于Mono不提供相同的保证,我选择安全并使用volatile关键字。 – 2012-07-18 14:09:09