2011-02-03 58 views
3

我有一个由两个函数调用分隔的代码中的关键部分,如Start()End()。他们在执行期间使用Monitor来阻止其他线程。现在我的问题是,如果某个线程无论出于何种原因都不会拨打End(),我的整个过程都会遇到麻烦,因为每个线程都在等待这个Monitor的发布。从监视器的所有者的另一个线程释放锁

当然我可以使用TryEnter超时,这样我就不会永久等待,但是这不会释放被阻止的Monitor,所以我的程序每次都会从这个时间开始进入这个超时。

如果给定的超时结束,是否有办法从另一个线程释放阻塞Monitor

void Start(){ Monitor.Enter(obj); } 

void End(){ Monitor.Exit(obj); } 

编辑: 我们通过COM调用Excel互操作,我们不能确保预期Excel进程将一直工作。请注意,这是一个Web应用程序,因此未能处理这种情况是致命的。 Start()称为第一次,请求调用excel函数,End()在请求结束时调用。 excel过程总是有可能开始挂起。

EDIT2: 我现在HDA的想法耳鼻喉科锁的所有者存储在变量和僵局,我可以杀了这个线程。这不会释放锁吗?

     if (Monitor.TryEnter(excelLocker, 10000) == false) 
         { 
          excelOwner.Abort(); 
          excelOwner = null; 
         } 
         else 
         { 
          excelOwner = Thread.CurrentThread; 
         } 
+0

为什么不在你的方法中设置一些简单的(...),直到达到某个阈值,然后在那一刻爆发? – 2011-02-03 17:17:32

+2

不要试图修补代码中的错误。修复错误。 – 2011-02-03 17:24:53

+0

@Hans Passant:这不是为了解决*我们的错误。我们通过com interop调用Excel,但我们无法确定Excel过程将始终按预期工作。请注意,这是一个Web应用程序,因此未能处理这种情况是致命的。 – codymanix 2011-02-03 17:35:26

回答

0

也许,但你只是隐藏了真正的问题。

你真正需要弄清楚的是为什么你的锁没有被释放。如果这是C++,你应该使用一个警卫(这样即使发生某些事情也会释放锁)。

2

唯一可以释放锁的线程是拥有该锁的线程。所以不,你不能直接从另一个线程“解锁”显示器 - 这是不可能的设计。如果你能够做到这一点,其他线程就可以通过释放它来覆盖锁的语义,因为它们实际上并不拥有它。

我很想知道为什么你不使用lock块,以便保证EnterExit,而不是直接使用Monitor

更新

阅读您的评论我会强烈建议组织代码,这样就可以定位你的锁,而不是要求起动,并要求结束之后。如果您使用lock,则仍然可以序列化对Excel的访问,但可以保证调用EnterExit

FYI a lock是一个Monitor在引擎盖下。

lock(_syncObj) 
    { 
     //Do stuff 
    } 

    //Is equivalent to 

    Monitor.Enter(_syncObj); 
    try 
    { 
     //Do stuff 
    } 
    finally 
    { 
     Monitor.Exit(_syncObj); 
    } 

使用lock可以按如下方式定位您的Excel锁定:

//Client code 
    ExcelUtil.DoStuff("bling") 

    //... 

    //Util class manages call to Excel and locking. 
    public static class ExcelUtil 
    { 
     private static readonly object SyncObj = new object(); 

     public static void DoStuff(string someParam) 
     { 
      //Guaranteed locking and unlocking even if an exception occurs 
      lock (SyncObj) 
      { 
       DoSomeStuffWithExcelFuncA(); 
       DoSomeStuffWithExcelFuncB(); 
      } 
     } 

     private static void DoSomeStuffWithExcelFuncA() 
     { 
      //... 
     } 

     private static void DoSomeStuffWithExcelFuncB() 
     { 
      //... 
     } 
    } 

顺便说一句,你为什么锁定访问到Excel?我猜你正在为你的ASP.Net应用程序使用Excel自动化服务器端。除非事态明显发展,否则这至少在几年之后总是非常麻烦。如果你拿出一个锁并且Excel挂起,你就塞满了。可以使用第三方解决方案来代替Excel自动化。也许更新版本的Excel就像这样被使用?

你的模式出现,以连载的所有请求,以便只有一个单一的(基于Excel)的请求可以在任一周时间被执行 - 这似乎并不很理想。

0

>>如果某个线程简化版,调用完()不管是什么原因,我的整个过程是麻烦,因为每个线程正在等待得到释放这个监视器。

让准确地说,我看到2个原因,一些线程不通话结束():

  • 此线程仍在执行,它是OK的情况,除非你试图使用资源这不可用此刻并继续尝试。因此,如果你尝试手动停止这个线程(从另一个线程就像你说的),那么你有危险,你的数据将处于不一致的状态 - 就像调用Thread.Abort()一样。

  • 正常的执行流程被异常打破。因此,您需要清理资源并在简单的try/finally块中释放此监视器。

更新

如果是Excel是它往往会抛出异常,通知它在高负载下不可用。最近在Code Review. StackExchange讨论了这个话题,以及如何处理这种情况。

另一种策略来应对情况下,当你不确定你会等待多久上的锁是使用Monitor.TryEnter(object, ref bool)。它是专门设计用于您不想在显示器上等待一段时间但采取其他一些操作的情况 - 因此您根本不会阻止。

相关问题