【问题标题】:Is it possible to get a count of queued threads waiting with Monitor.Enter?是否可以使用 Monitor.Enter 获得排队线程的计数?
【发布时间】:2019-10-18 21:19:34
【问题描述】:

我正在运行一些非线程安全的单例代码,并且需要一些时间才能运行。 它偶尔会被多个用户同时调用,所以我使用 Monitor 来处理处理请求排队,如下所示;

bool lockWasTaken = false;
try
{
    Monitor.TryEnter(lockObject, ref lockWasTaken); // returns lockWasTaken = true if it can get a lock
    if (!lockWasTaken)
    {
        log.Warn("Locked by existing request. Request is queued.");
        Monitor.Enter(lockObject, ref lockWasTaken); // Goes into the queue to access the object
    }

    // Do the Singleton processing

}
catch(Exception ex)
{
    log.Fatal(ex);
}
finally
{
    if (lockWasTaken)
    {
        Monitor.Exit(lockObject);
    }
}

这一切都很好。但我想做的是能够记录有多少排队的请求。 这可能吗?

【问题讨论】:

  • 如果你的if (!lockWasTaken) { 块中有一个正在更新的静态变量怎么办。这行得通吗?
  • 答案是否定的
  • 你看过Interlocked类,方法IncrementDecrement吗?

标签: c# multithreading locking


【解决方案1】:

感谢@Theodor Zoulias 使用 Interlocked 类为以下解决方案指明了正确的方向;

private static readonly Object lockObject = new Object(); // just a random object used to decide whether the thread has locked the Singleton functions
private static int queueCount = 0; // tracked across multiple threads

bool lockWasTaken = false;
try
{
    // Increments the queueCount variable across multiple threads
    // https://docs.microsoft.com/en-us/dotnet/api/system.threading.interlocked.increment?view=netframework-4.8
    int currentQueueCount = Interlocked.Increment(ref queueCount);

    Monitor.TryEnter(lockObject, ref lockWasTaken); // returns lockWasTaken = true if it can get a lock
    if (!lockWasTaken)
    {
        log.Warn("Locked by existing request. Request is queued. Queue length is " + (currentQueueCount - 1).ToString()); // subtract since the first request is already processing
        Monitor.Enter(lockObject, ref lockWasTaken); // Goes into the queue to access the object
    }

    // Do the Singleton processing

}
catch(Exception ex)
{
    log.Fatal(ex);
}
finally
{
    if (lockWasTaken)
    {
        Monitor.Exit(lockObject);
    }
    // Reduce the queue count
    Interlocked.Decrement(ref queueCount);
}

【讨论】:

  • 您应该使用从 Interlocked.Increment(ref queueCount); 返回的 int 而不是 queueCount 本身,因为该值可能会在 TryEnter 和您的日志警告之间发生变化。从增量调用返回的 int 将始终是增量后的新值。
猜你喜欢
  • 2021-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-18
  • 1970-01-01
  • 1970-01-01
  • 2014-12-10
相关资源
最近更新 更多