1

我们的 Web 应用程序中有几个 full lock-s,如果将它们替换为读写锁,它们的性能可能会更高——即使有 RW 锁的额外开销,我们的代码也会更加并行。不幸的是,我不能使用ReaderWriterLockSlim,因为它看起来像一个相当大的同步错误,可能导致某些硬件上的死锁。这篇文章非常详细地解释了这个问题。

上述问题似乎已在 .NET Framework 4.0.30319.33440 中得到修复,但并非所有 Windows 服务器版本都得到此修复。Windows 8.1 和 Windows Server 2012 R2 已修复。Windows Server 2012(不是 R2)和 Windows Server 2008 R2 仍然存在错误,即使在最新补丁之后。看起来微软不打算在所有平台上解决这个问题。

我们的各种服务器环境使用不同版本的 Windows Server,我已经确认有些服务器有修复,而有些则没有。这意味着我不能安全地将所有这些lock语句更改为读写器锁,因为在我们的某些服务器上,应用程序可能会随机死锁。

作为替代方案,我正在研究ReaderWriterLockSlim通过反编译 System.Core 中的代码并创建一个新类(类似于MyRWLock)来重新实现,该类修复了一个(已知)错误功能ExitMyLock。所有其他代码与原始代码相同ReaderWriterLockSlim

这需要删除所有__DynamicallyInvokable属性并添加 2 或 3 个内部的类/结构System.Core。我做了所有这一切,并让新的锁类编译没有错误。

我的问题是:谁能想到这个新课程不能像原来的ReaderWriterLockSlim课程那样工作的任何原因?我认为自己在线程方面相当出色,但我不是专家。由于我没有更改任何代码(除了修复一些类型名称以指向新MyRWLock的而不是ReaderWriterLockSlim属性),我相信这应该可行。但是,我确实想知道,如果我忘记了一些可能会以各种难以调试的有趣方式破坏这一点的东西。

或者:我(和链接的文章)的理解是错误的吗?这个问题不需要首先解决吗?那篇文章的作者似乎做了一个非常详细的分析,这对我来说是正确的,但微软并未将更改应用于某些 Windows Server 版本。

对此的任何想法将不胜感激。

编辑

要为全锁添加更多上下文,这就是它们的用途。我们有一个服务,它在执行其工作时读取/写入远程服务。读比写多得多。一次读取涉及到 1 次网络往返,一次写入涉及到远程服务的 3 次网络往返。当发生写入时,可能不会发生读取(写入实际上是读取->删除->添加)。现在,我们对lock所有这些操作都使用 full -s ,但这意味着所有尝试读取的线程仍然必须排队,直到当前读取完成,即使没有写入。在我看来,RW 锁将是理想的选择。

4

1 回答 1

1

文章准确吗?我不知道。他们至少指出 .NET 中的更新解决了他们声称存在的问题,这表明确实存在。另一方面,它是否适用于您仍然存在问题。无论如何,桌面 x86 机器对所有内存访问都具有 volatile 语义,所以如果描述的唯一错误是缺少显式的 volatile 操作,那么对于大部分硬件来说,这不是问题。

在大型服务器硬件上,架构是不同的,它们可能有不同的语义,需要明确的易失性操作。那是你可能想要研究的东西。

当然,不管硬件架构如何,“volatile”对于 .NET 编译器也是有意义的。在我看来,文章中引用的代码不会受到编译器优化的影响,但我不是该领域的专家,所以我不能肯定地说。

我从您实际上没有目睹此错误发生的问题中得出结论。在这一点上,这纯粹是假设性的问题。

我会警惕尝试重新实现这种类型的类,即使使用原始源作为起点。

我的第一选择是确保我已升级到足够新的 .NET 版本,以修复您引用的文章中描述的错误。

第二个选择是使用普通的 ReaderWriterLock 类而不是 ReaderWriterLockSlim。

第三种选择是使用本机 Win32“苗条读/写锁”结构(即通过 p/invoke 或 C++/CLI)。

只有当这些选项都没有被证明是可行的时,我才会去麻烦实现我自己的读写锁,你可以打赌我不会尝试“苗条”的变体(即所有棘手的无锁的东西......我可以看到使用一个 volatile 标志,但除此之外只使用Monitor基于传统的代码)。

于 2014-10-24T00:41:15.980 回答