【问题标题】:Locking critical section in object used across multiple threads锁定跨多个线程使用的对象中的关键部分
【发布时间】:2014-02-26 00:07:15
【问题描述】:

我有一个在任意数量的线程中实例化的类,这些线程根据需要进行假脱机。这意味着在任何时候都可以使用该类的任意数量的实例化版本,并且该类的一部分需要锁定以防止并发访问。

为了防止各个线程之间出现数据问题,我需要一种方法来锁定一段代码,使其与其他线程中的其他实例化版本的类不兼容。由于这个类可以有多个实例化版本,我不能只使用私有成员变量来锁定(而且我知道不要使用 Type 或任何可公开访问的东西);所以我使用了一个私有静态成员变量。

这是解决这个问题的合理方法吗?还是有更好的解决方案?

示例代码如下:

public class MyClass
  {
    private static object LockingVar = new object();

    public void MyPublicMethod()
    {
      lock (LockingVar)
      {
         // Do some critical code
      }
  }

编辑

MyPublicMethod 正在调用本地 SQLExpress 实例,除了更新和插入之外,它还可以执行选择,因此它需要在另一个线程进入并将其搞砸之前完成。

【问题讨论】:

  • 1) 您锁定共享资源以防止损坏,2) 如果共享资源是基于实例的[即多个线程访问单个类实例],您的LockingVar [通常称为 SyncRoot] 应该是基于实例的'private readonly object LockingVar', 3) 如果共享资源是基于静态的[即许多实例,每个线程一个,每个实例引用一个静态列表],那么您的锁也应该是静态的。 fwiw,我会避免任何静态的东西,但我们必须做我们必须做的:)
  • 鉴于您的编辑 - 您不能依靠数据库事务来确保并发选择/插入/更新不会相互破坏,而不是在调用代码中使用相当残酷的锁定吗?跨度>
  • 我会这么认为,只是它不只是进行数据库调用。它还在对关键/共享数据进行更改。这会改变现状吗?在这一点上,我意识到我本可以提供有关我的确切解决方案的更多详细信息。
  • 根据这里 (docs.microsoft.com/en-us/dotnet/csharp/language-reference/…) :最佳做法是定义一个私有对象来锁定,或者定义一个私有静态对象变量来保护所有实例共有的数据。

标签: c# locking


【解决方案1】:

我觉得不错。我还将 LockingVar 标记为只读。

【讨论】:

  • @RichardOD 仅供我理解,为什么要将私有字段标记为只读?
【解决方案2】:

是的,通过您的示例代码,您将获得该类所有实例的方法的全局关键部分。

如果这就是您要寻找的(并且您必须问自己是否真的希望一次只让一个线程运行该方法),您也可以使用[MethodImpl(MethodImplOptions.Synchronized)],它使您基本相同功能。

[MethodImpl(MethodImplOptions.Synchronized)]
public static void MyPublicMethod()
{
     // Do some critical code
}

注意:如果是实例方法,这相当于写lock(this){},如果是类(静态)方法,则写lock(typeof(MyClass))。两者都不受欢迎,所以你的lock(obj) 模式更好。

【讨论】:

  • 如果您只想锁定单个实例而不是所有实例,请删除静态修饰符。
【解决方案3】:

来自 MSDN:

最佳实践是定义一个私有对象来锁定,或者定义一个私有静态对象变量来保护所有实例共有的数据。

http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx

因此您的实现似乎是正确的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-31
    • 1970-01-01
    • 1970-01-01
    • 2017-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多