【问题标题】:Difference between manual locking and Synchronized methods手动锁定和同步方法之间的区别
【发布时间】:2011-09-02 15:50:53
【问题描述】:

这有什么区别:

internal class MyClass
{
    private readonly object _syncRoot = new Object();

    public void DoSomething() 
    {
        lock(_syncRoot)
        {
            ...
        }
    }

    public void DoSomethingElse() 
    {
        lock(_syncRoot)
        {
            ...
        }
    }
}

还有这个:

internal class MyClass
{
    [MethodImpl(MethodImplOptions.Synchronized)]
    public void DoSomething() 
    {
        ...
    }

    [MethodImpl(MethodImplOptions.Synchronized)]
    public void DoSomethingElse() 
    {
        ...
    }
}

我看到的唯一区别是第一种方法锁定了某个私有成员,而第二种方法锁定了实例本身(因此它应该锁定实例中的所有其他内容)。有什么一般建议使用哪种方法?我目前在我们的项目中发现了两个具有相似目的的类,每个类都用不同的方法编写。

编辑:

也许还有一个问题。这是:

internal class MyClass
{
    [MethodImpl(MethodImplOptions.Synchronized)]
    public void DoSomething() 
    {
        ...
    }
}

完全一样:

internal class MyClass
{
    public void DoSomething() 
    {
        lock(this) 
        {
            ...
        }
    }
}

【问题讨论】:

  • @Winston:太好了。我的问题几乎是重复的。
  • 我会将属性形式视为对编译器的“礼貌建议”。我不确定他们是否受标准的约束来遵循它。而显式使用 lock 语句会强制执行编译时间要求。
  • @sixlet 礼貌的建议不会很有用/可靠,不是吗?
  • @Henk:我只是说我不记得它被任何标准锁定为“必须由合规的 CLR 实施”。

标签: c# .net multithreading locking


【解决方案1】:

首选第一种方法,因为您可以(并且应该)将_syncRoot 设为私有。这降低了死锁的风险。

MethodImplOptions.Synchronized 是早期雄心勃勃的想法的遗留物,结果证明它并不是那么好。

关于最后一个问题:是的,根据this blog,它们在功能上是等效的(但实现方式不同)。并且不鼓励所有形式的lock(this),同样是因为死锁场景。

【讨论】:

  • 公共可用性等。
  • 确实,任何人都可以锁定是这里提到的问题blogs.msdn.com/b/bclteam/archive/2004/01/20/60719.aspx
  • 仅在 private 方法中使用 'MethodImplOptions.Synchronized' 怎么样?
  • @samsara 存在相同的“问题”,因为无论方法可见性如何,都会获取 instance(或静态方法的类型)上的锁定。如果某些“其他错误代码”获得了实例上的锁定,那么它可能导致意外锁定,甚至死锁;因此“最佳实践”建议是 “all” 锁定对象 - 除非有意暴露(如 SyncRoot),而不是通过意外的副作用/出血暴露 - 被隐藏起来外面的世界。
【解决方案2】:

查看http://blogs.msdn.com/b/bclteam/archive/2004/01/20/60719.aspxhttp://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_20926988.html
他们也讨论了lock(this),并且不鼓励使用它,因为:

完全不相关的代码也可以选择锁定该对象

引用自 EE:

如果你锁定了一个对象,所有其他需要访问这个特定对象的线程都会等待,直到另一个对象完成。但是,如果您将方法标记为同步,则此特定方法将不会在多个线程上执行。 Lock 保护对象,Synchronized 保护方法。

【讨论】:

  • 是的,我知道这个问题。在 MSDN 中直接指出,Synchronized 方法不应该用于公共类。
  • +1 表示第二个报价。这是 IMO 两种机制之间最重要的区别。
  • “这种特殊的方法不会在多个线程上执行”为我赢得胜利,代码更少,简单,1 行......漂亮!正是我需要的。如果我有很多线程在狂奔,lock() 将变成地狱
  • EE 的引用是错误的。根据documentationSynchronized 表示:该方法一次只能由一个线程执行。静态方法锁定类型,而实例方法锁定实例。只有一个线程可以在任何实例函数中执行,并且只有一个线程可以在任何类的静态函数中执行。 所以不,它与这种特殊方法无关。当一个线程执行MethodA时,另一个线程无法进入MethodB
【解决方案3】:

随便看了一眼,发现便携设备不支持MethodImplOptions.Synchronized。

还有一句话:

锁定实例或 类型,与同步标志一样, 不推荐用于公共类型, 因为你自己的代码可以 锁定公共类型和 实例。这可能会导致死锁 或其他同步问题。

来源:http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.methodimploptions%28v=VS.100%29.aspx

【讨论】:

  • 我知道MSDN的描述。我的课程不公开。
【解决方案4】:

我认为差异将取决于装饰方法中引用的对象。根据我的阅读,装饰实际上在 IL 中实现了 lock() 。

最好的方法是根据需要进行最具体的锁定。

【讨论】:

    【解决方案5】:

    这篇文章可能对你有所帮助:http://www.yoda.arachsys.com/csharp/threads/lockchoice.shtml

    通常我会避免锁定“this”,因为私有锁定变量可以提供更好的控制。如果需要的话,我建议锁定“this”,如果它是自定义集合类,类似于 SyncRoot 的内容。

    哈桑

    【讨论】:

      猜你喜欢
      • 2015-07-25
      • 2014-09-30
      • 1970-01-01
      • 1970-01-01
      • 2014-04-27
      • 2021-10-16
      • 1970-01-01
      • 1970-01-01
      • 2017-04-24
      相关资源
      最近更新 更多