【问题标题】:Is there any way to determine the number of threads waiting to lock in C#?有没有办法确定等待锁定在 C# 中的线程数?
【发布时间】:2010-12-15 21:23:21
【问题描述】:

我在 C# 中使用 lock 语句进行简单锁定。有什么方法可以确定有多少其他线程在等待锁定对象?我基本上想将等待锁的线程数限制为 5。如果第六个线程需要获得锁,我的代码会抛出异常。

【问题讨论】:

  • 这听起来像是繁琐解决方案的后半部分。您要解决的实际问题是什么?
  • 很难解释,但我有一个对象,它是第三方 Web 服务的包装器。诀窍是必须同步对第 3 方服务的调用,因此锁定了包装器对象。我在网站环境中使用包装器对象,因此多个线程可以尝试同时使用它。我想将等待线程队列限制为 5 个的原因是我有点担心创建 DoS 附加会多么容易。第 3 方网络服务非常慢,因此有人可以轻松发送请求,而我将有 100 个阻塞线程。
  • @Ben:听起来您需要限制的资源是系统中的线程数,而不是可以等待多少个锁我>。永远不要为每个请求创建一个线程;每个处理器创建一个线程,如果处理器用完,让客户端等待线程释放。
  • @Eric:我不确定,但 ASP.NET 不是每个请求使用 1 个线程吗?也许我错了,阻止 ASP.NET 线程会阻止我的网站为更多请求提供服务,直到线程不再被锁定。那会很糟糕。
  • @Eric:我对多线程了解不多,但是应该为每个处理器或每个内核创建 1 个线程,还是这取决于要解决的问题?

标签: c# multithreading locking


【解决方案1】:

这可以通过Semaphore 类轻松完成。它会为你计算。请注意,在下面的代码中,我使用信号量对等待资源的线程数进行非阻塞检查,然后使用普通的旧 lock 来实际序列化对该资源的访问。如果等待资源的线程超过 5 个,则会引发异常。

public class YourResourceExecutor
{
  private Semaphore m_Semaphore = new Semaphore(5, 5);

  public void Execute()
  {
    bool acquired = false;
    try
    {
      acquired = m_Semaphore.WaitOne(0);
      if (!acquired)
      {
        throw new InvalidOperationException();
      }
      lock (m_Semaphore)
      {
        // Use the resource here.
      }
    }
    finally
    {
      if (acquired) m_Semaphore.Release();
    }
  }
}

这种模式有一个值得注意的变化。您可以将方法的名称更改为 TryExecute 并让它返回 bool 而不是抛出异常。这完全取决于您。

请记住,锁定表达式中使用的对象不是锁定的主题。它仅用作同步代码块的标识符。任何使用相同对象获取锁的代码块都将被有效地序列化。被“锁定”的是代码块,而不是 lock 表达式中使用的对象

【讨论】:

  • 我想我明白这一点,但是当 m_Semaphore 使用 lock() 锁定时,任何其他线程可以获取信号量锁吗?我想知道 lock() 是否应该在一个单独的对象上。
  • @Ben:是的,您绝对可以为lock 使用单独的对象。我只是选择使用一个已经存在的对象,而不是创建一个单独的对象。在Semaphore 上使用lock 绝不会影响Semaphore 的行为。
  • @Brian,我是新手,但我认为如果你通过 lock() 锁定了一个对象,那么没有其他线程可以以任何方式访问该对象。
  • @Ben:不,lock 表达式中使用的对象不是锁定的主题。它仅用作同步代码块的标识符。任何使用 same 对象获取锁的代码块都将被有效地序列化。被“锁定”的是代码块,而不是 lock 表达式中使用的对象。
  • @Brian:很高兴知道。非常感谢您的回答。这正是我正在寻找的。有什么理由不使用 SemaphoreSlim?
【解决方案2】:

lock 语句是Monitor.EnterMonitor.Exit 的快捷方式。我不认为,您有机会获得等待对象的数量。

【讨论】:

    【解决方案3】:

    您可以使用在锁定语句之前递增的简单共享计数器(整数)。如果该值等于 5,则让您的线程避免使用 lock 语句。然而,挑战在于您需要锁定计数器以确保增量操作是原子的。

    【讨论】:

    • 你可以为此做 Interlocked.Increment。
    • +1 康拉德的建议;可能是实现这一点的最简单方法。
    【解决方案4】:

    不,lock() 使用 Monitor class 并且它没有用于找出排队线程的 nr 的成员。

    您可以指定超时。

    坦率地说,当队列填满时抛出异常听起来是个坏主意。

    【讨论】:

      猜你喜欢
      • 2011-10-27
      • 1970-01-01
      • 2018-11-30
      • 1970-01-01
      • 2014-12-22
      • 1970-01-01
      • 2021-04-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多