C# 锁定语句

发布于 2024-11-29 09:29:39 字数 325 浏览 3 评论 0原文

当一个线程尝试进入临界区并获取锁时,它实际上在做什么?

我问这个问题是因为我通常创建一个对象(对象类型),该对象仅用于锁定目的。 考虑以下内容:我想编写一个接受集合的方法,以及一个用作锁定对象的对象,因此该方法内的整个集合操作将在关键部分中声明,该关键部分将由该给定对象锁定。

我应该使用“ref”传递该锁定对象还是传递该对象的引用副本就足够了?换句话说,由于 lock 语句仅与引用类型一起使用,因此该机制是否检查引用对象的值,还是检查指针的值?因为显然,当传递一个没有“ref”的对象时,我实际上得到了引用的副本,而不是引用本身。

When a thread tries to enter a critical section and obtain a lock, what is it actually doing?

I'm asking this because I usually create an object (of type object) which will serve for locking purposes only.
Consider the following: I want to write a method which accepts a collection, and an object which will serve as the locking object so the whole collection manipulation inside that method will be declared inside the critical section which will be locked by that given object.

Should I pass that locking object using "ref" or is passing a reference copy of that object is enough? In other words - since the lock statement is used with reference types only, does the mechanism check the value of the referenced object, or does it check the pointer's value? because obviously, when passing an object without "ref", I actually get a copy of the reference, and not the reference itself.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

成熟的代价 2024-12-06 09:29:39

这是您可以遵循的典型锁定模式。基本上,您可以创建一个锁定对象,用于锁定对关键部分的访问(正如 @Hans 所说,它并不保护您正在处理的对象 - 它只是处理锁)。

class ThreadSafe
{
  static readonly object _locker = new object();
  static int _val1, _val2;

  static void Go()
  {
    lock (_locker)
    {
      if (_val2 != 0) Console.WriteLine (_val1 / _val2);
      _val2 = 0;
    }
  }
}

此示例来自 Joseph Albahari 的有关线程的在线书籍。它很好地概述了创建 lock 语句时发生的情况,以及有关如何对其进行最佳优化的一些提示/技巧。绝对强烈推荐阅读。

根据 Albahari 的说法,lock 语句在 .NET 4 中翻译为:

bool lockTaken = false;
try
{
  Monitor.Enter (_locker, ref lockTaken);
  // Do your stuff...
}
finally { if (lockTaken) Monitor.Exit (_locker); }

它实际上比直接使用 Monitor.Enter 然后调用 Monitor.Exit 更安全> 在您的 finally 中,这就是它被添加到 .NET 4 中的原因。

Here's a typical pattern that you can follow for locking. Basically, you can create a locking object that is used to lock access to your critical section (which, as @Hans said, is not protecting the object that you're working on -- it just handles the lock).

class ThreadSafe
{
  static readonly object _locker = new object();
  static int _val1, _val2;

  static void Go()
  {
    lock (_locker)
    {
      if (_val2 != 0) Console.WriteLine (_val1 / _val2);
      _val2 = 0;
    }
  }
}

This example was from Joseph Albahari's online book on threading. It provides an excellent overview of what's going on when you create a lock statement and some tips/tricks on how to best optimize for it. Definitely highly recommended reading.

Per Albahari, again, the lock statement translates in .NET 4 as:

bool lockTaken = false;
try
{
  Monitor.Enter (_locker, ref lockTaken);
  // Do your stuff...
}
finally { if (lockTaken) Monitor.Exit (_locker); }

It's actually safer than a straight Monitor.Enter and then calling Monitor.Exit in your finally, which is why it was added in .NET 4.

向地狱狂奔 2024-12-06 09:29:39

无需传递 ref 即可锁定对象lock 实际上做的是,调用
Monitor.Enter 位于开头该块和 Monitor.Exit 退出时。

希望这有帮助。

It's enough to lock the object without passing ref. What lock actually does is, call
Monitor.Enter on the beginning of the block and Monitor.Exit on exit.

Hope this helps.

望她远 2024-12-06 09:29:39

MSDN 这里说关于锁定

使用 Enter 获取作为参数传递的对象上的监视器。如果另一个
线程已对对象执行了 Enter 但尚未执行相应的 Exit,
当前线程将阻塞,直到另一个线程释放该对象。这是合法的
同一线程多次调用 Enter 而不会阻塞;然而,一个平等的
在等待该对象的其他线程之前,必须调用 Exit 调用的次数
解锁。

因此您不需要将其作为 ref 传递,简单的按引用传递即可。

这意味着它与引用或指针无关,而是与引用指向的实际对象有关, lock 请参阅 this 问题的答案,其中显示

“lock 语句由 C# 翻译”至以下内容:”

var temp = obj;

Monitor.Enter(temp);

try
{
    // body
}
finally
{
    Monitor.Exit(temp);
}

MSDN says here about lock

Use Enter to acquire the Monitor on the object passed as the parameter. If another
thread has executed an Enter on the object but has not yet executed the corresponding Exit,
the current thread will block until the other thread releases the object. It is legal for
the same thread to invoke Enter more than once without it blocking; however, an equal
number of Exit calls must be invoked before other threads waiting on the object will
unblock.

which means it's not about the reference or pointer it is about the actual object which is pointed by the reference so you won't need to pass as ref simple pass by reference will work

Regarding what actually happens inside the lock see answer to this question which says

"The lock statement is translated by C# to the following:"

var temp = obj;

Monitor.Enter(temp);

try
{
    // body
}
finally
{
    Monitor.Exit(temp);
}
兔姬 2024-12-06 09:29:39

我应该使用“ref”传递该锁定对象还是传递该对象的引用副本就足够了?

可能两者都不是。如果您有一些非线程安全的资源,最好的选择通常是仅从一个类直接访问该资源,该类具有一个锁对象作为字段(或者您可以直接锁定该资源)。如果您将锁对象传递给其他人,则很难确保代码仍然可以正常工作,例如,锁定是在应该完成的时候完成的,并且没有死锁。

但是,如果您确实想传递锁对象,则不需要使用 ref,正如其他人指出的那样。锁定是在对象的实例上完成的,而不是在包含对其引用的变量上完成的。

Should I pass that locking object using "ref" or is passing a reference copy of that object is enough?

Probably neither. If you have some resource that is not thread-safe, the best option usually is to access that resource directly only from one class, which has a lock object as a field (or you can lock directly on the resource). If you pass the lock object to others, it's hard to make sure that the code will still work properly, e.g. locking is done when it should and there are no deadlocks.

But if you really want to pass the lock object, you don't need to use ref, as others have pointed out. Locking is done on the instance of the object, not on the variable containing reference to it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文