如果另一个线程已获得关键部分的锁定,如何停止线程?

时间:2015-10-15 03:56:05

标签: c# multithreading

我创建了一个调度程序,它在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
   }
}

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

2 个答案:

答案 0 :(得分:2)

您可以使用Monitor

MSDN:

  

Monitor类通过向单个线程授予对象锁来控制对对象的访问。对象锁提供了限制对代码块的访问的能力,通常称为关键部分。虽然线程拥有对象的锁,但没有其他线程可以获取该锁。您还可以使用Monitor类来确保不允许其他线程访问由锁所有者执行的应用程序代码部分,除非另一个线程使用其他锁定对象执行代码。 More please...

但你可能会问,“不是c#的lock()所做的吗?”并且在某些方面是肯定的。然而,关于Monitor的一个非常好的事情是你可以尝试获得一个锁并且指定一个超时来等待而不是阻塞线程直到可能结束时间或者至少直到你有读完了战争与和平的副本。

Mutex不同,Monitor的重量轻!就像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...

答案 1 :(得分:1)

尝试以下:

 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。就是这样!