问答中心分类: C#为什么lock(this){…}令人不快的
0
Anton 提问 1天 前

这个MSDN文档他说

public class SomeObject
{
  public void SomeOperation()
  {
    lock(this)
    {
      //Access instance variables
    }
  }
}

是“如果实例可以公开访问,则会出现问题”。我想知道为什么?是不是因为锁的使用时间过长?还是有更阴险的原因?

16 Answers
0
Orion Edwards 回答 1天 前

因为如果人们可以访问你的对象实例(即:你的this)指针,则它们也可以尝试锁定同一对象。现在他们可能不知道你正在锁定this内部,因此这可能会导致问题(可能是死锁)
除此之外,这也是一种不好的做法,因为它锁定“太多”
例如,您可能有一个成员变量List<int>,而实际上唯一需要锁定的是该成员变量。如果在函数中锁定整个对象,那么调用这些函数的其他对象将被阻止,等待锁定。如果这些函数不需要访问成员列表,那么您将导致其他代码等待并无缘无故地降低应用程序的速度。

Esteban Brenes 回复 1天 前

这个答案的最后一段不正确。锁定不会以任何方式使对象不可访问或只读。锁定(this)不会阻止另一个线程调用或修改此引用的对象。

Herms 回复 1天 前

如果调用的其他方法也执行锁定(this),则会执行此操作。我相信这就是他说的重点。注意“如果在函数中锁定整个对象”。。。

Esteban Brenes 回复 1天 前

@猎户座:那更清楚了@Herms:是的,但您不需要使用“this”来实现该功能,例如,列表中的SyncRoot属性可以实现该目的,同时明确应该在该键上进行同步。

Zan Lynx 回复 1天 前

回复:锁定“太多”:决定锁定什么是一个很好的平衡行为。请注意,获取锁涉及缓存刷新CPU操作,而且成本有点高。换句话说:不要锁定和更新每个单独的整数。:)

Joakim M. H. 回复 1天 前

最后一段仍然没有意义。如果只需要限制对列表的访问,那么如果其他函数不访问列表,为什么会有锁?

Orion Edwards 回复 1天 前

@约阿基姆。H、 -假设您有一个列表,然后还有一个整数,您希望限制对这两个列表的访问。如果两个锁不需要锁在一起(锁得太多),那么它们周围的单个锁可能会有问题,因此您可以选择使用两个锁来代替

Joakim M. H. 回复 1天 前

没错,但段落中说,列表是唯一需要锁定的东西。

0
crashmstr 回答 1天 前

查看MSDN主题线程同步(C#编程指南)

通常,最好避免锁定这可能会造成. 锁定公共

0
Craig 回答 1天 前

我知道这是一条古老的线索,但因为人们仍然可以查找并依赖它,所以指出这一点似乎很重要lock(typeof(SomeObject))明显比lock(this). 话虽如此;感谢Alan指出lock(typeof(SomeObject))是不好的做法。
的实例System.Type是最通用的粗粒度对象之一。至少是系统的一个实例。类型对于AppDomain是全局的,并且。NET可以在AppDomain中运行多个程序。这意味着,如果两个完全不同的应用程序都试图在系统的同一全局实例上获得同步锁,则它们可能会相互干扰,甚至可能导致死锁。类型
所以lock(this)不是特别健壮的形式,可能会导致问题,并且应该总是对引用的所有原因感到惊讶。尽管我个人更希望看到这种模式发生变化,但像log4net这样的代码被广泛使用、相对受人尊重且明显稳定,它广泛使用锁(this)模式。
但是lock(typeof(SomeObject))打开了一个全新的增强蠕虫罐。
为了它的价值。

0
Alan 回答 1天 前

…同样的论点也适用于这个结构:

lock(typeof(SomeObject))
Craig Tullis 回复 1天 前

lock(typeof(SomeObject))实际上比lock(this)糟糕得多(堆栈溢出。电话:10510647/618649).

Zar Shardan 回复 1天 前

那么,lock(Application.Current)就更糟糕了,但谁会尝试这些愚蠢的事情呢?lock(this)似乎合乎逻辑且简洁,但其他示例则不然。

Craig Tullis 回复 1天 前

我不同意lock(this)似乎特别合乎逻辑和简洁。这是一个非常粗糙的锁,任何其他代码都可能锁定您的对象,可能会对您的内部代码造成干扰。采取更细粒度的锁,并采取更严格的控制。什么lock(this)这比lock(typeof(SomeObject)).

0
atlaste 回答 1天 前

想象一下,你的办公室里有一位技术娴熟的秘书,这是部门的共享资源。偶尔,你会因为有任务而冲向他们,只希望你的另一位同事还没有认领他们。通常你只需要等待一小段时间。
因为关怀就是分享,所以您的经理决定客户也可以直接使用秘书。但这有一个副作用:当您为客户工作时,客户甚至可能会提出索赔,您还需要他们执行部分任务。出现死锁,因为声明不再是层次结构。如果一开始不允许客户索赔,这本可以全部避免。
lock(this)就像我们看到的那样糟糕。外部对象可能会锁定该对象,由于您无法控制谁在使用该类,任何人都可以锁定该对象。。。这就是如上所述的确切示例。同样,解决方案是限制对象的曝光。但是,如果您有private,protectedinternal给你上课可能已经控制谁锁定了您的对象,因为您确信自己已经编写了代码。所以这里的信息是:不要将其公开为public. 此外,确保在类似场景中使用锁可以避免死锁。
与此完全相反的是锁定在整个应用程序域中共享的资源,这是最坏的情况。这就像把你的秘书放在外面,让外面的每个人都来认领他们一样。结果是一片混乱——或者就源代码而言:这是个坏主意;扔掉它,重新开始。那我们怎么做呢?
正如大多数人指出的那样,类型在应用程序域中是共享的。但我们可以使用更好的东西:字符串。原因是字符串已合并. 换句话说:如果在应用程序域中有两个具有相同内容的字符串,则它们有可能具有完全相同的指针。由于指针用作锁键,因此基本上得到的是“为未定义的行为做好准备”的同义词。
类似地,您不应该锁定WCF对象HttpContext。当前,线程。当前、单例(一般)等。避免所有这些的最简单方法是什么?private [static] object myLock = new object();

Rashack 回复 1天 前

实际上,拥有一个私有类并不能阻止这个问题。外部代码可以获取对私有类实例的引用。。。

atlaste 回复 1天 前

@Rashack虽然您在技术上是正确的(指出这一点需要加1),但我的观点是,您应该控制锁定实例的人。返回这样的实例会破坏这一点。