【问题标题】:How to stop thread if another thread has acquired lock on critical section?如果另一个线程已获得关键部分的锁定,如何停止线程?
【发布时间】:2015-10-15 03:56:04
【问题描述】:

我创建了一个调度程序,它以 x 分钟的时间间隔执行一段程序。如果程序执行需要更多时间,则下一个作业不应等待当前作业完成。我正在使用System.Timers.Timer

_scheduler = new System.Timers.Timer(SomeMinutes);
_scheduler.Elapsed += new ElapsedEventHandler(OnTimedEvent);
_scheduler.Enabled = true;
_scheduler.AutoReset = true;

private void OnTimedEvent(object source, ElapsedEventArgs e)
{
   lock(obj)
   {
     //Critical Section
   }
}

如果我使用锁,下一个线程等待当前线程释放锁。我不想要这种行为。如果一个线程在临界区获得了锁对象,那么另一个线程应该退出而不执行临界区

【问题讨论】:

  • 我会认为指定一个超时时间,例如 cs.Lock(timeout) 就可以了?
  • 我没有得到 cs.Lock(timeout)。什么是cs对象?
  • 抱歉,实际上您需要使用Monitor,因为.NET 不像Mutex 那样包装操作系统关键部分。特别是Monitor.TryEnter

标签: c# multithreading


【解决方案1】:

您可以使用Monitor

MSDN:

Monitor 类通过将对象的锁授予单个线程来控制对对象的访问。对象锁提供了限制对代码块(通常称为临界区)的访问的能力。当一个线程拥有一个对象的锁时,没有其他线程可以获取该锁。您还可以使用 Monitor 类来确保不允许其他线程访问锁所有者正在执行的应用程序代码部分,除非其他线程正在使用不同的锁定对象执行代码。 More please...

但你可能会问,“这不是 c# 的 lock() 所做的吗?” 在某些方面是的。然而,Monitor 的真正好处在于,您可以尝试获取锁并 指定超时 等待而不是阻塞线程直到时间结束或至少直到您完成阅读战争与和平的副本。

另外,与Mutex 不同,Monitors 使用起来很轻!就像 Windows 操作系统的深层管道中的关键部分一样。

更改您的代码

private void OnTimedEvent(object source, ElapsedEventArgs e)
{
   lock(obj)
   {
     //Critical Section
   }
}

...到:

object _locker = new object();
const int SomeTimeout=1000;

private void OnTimedEvent(object source, ElapsedEventArgs e)
{
    if (!Monitor.TryEnter(_locker, SomeTimeout))
    {
        throw new TimeoutException("Oh darn");
    }

    try
    {
        // we have the lock so do something
    }
    finally
    {
        // must ensure to release the lock safely
        Monitor.Exit(_locker);
    }   
}

这是 MSDN 对 TryEnter 的评价:

在指定的毫秒数内尝试获取指定对象的排他锁 - Tell me more...

【讨论】:

    【解决方案2】:

    试试下面:

     ThreadPoolScheduler.Instance.Schedule(
        TimeSpan.FromSeconds(SomeSecondsSuchAs30), () => doNotWaitAnyMore());
    

    由于您正在处理任务调度作业,ThreadPoolScheduler 值得仔细研究。

    您也可以使用Polly,这可能会节省您的时间:

    Policy.Handle<TimeoutException>().Execute(() => {
        //Logic for no longer waiting current job, .e.g start a new job
        doNotWaitAnyMore();
    });
    

    在您的长期工作中,请发送TimeoutException。就是这样!

    【讨论】:

    • 我不想设置超时 SomeSecondsSuchAs30。这是神奇的数字。我不知道要设置什么值。我期待 .net 本机库来实现这一点,所以我不能使用 Polly
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 2015-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多