在以下情况下是不是存在死锁,有啥解决方案可以防止它?

Posted

技术标签:

【中文标题】在以下情况下是不是存在死锁,有啥解决方案可以防止它?【英文标题】:Is there a deadlock in following situation and what could be the solution to prevent it?在以下情况下是否存在死锁,有什么解决方案可以防止它? 【发布时间】:2020-09-20 17:00:27 【问题描述】:

我有一个FileLogger 类,它将消息记录到一个txt 文件。我的目的是使FileLogger 类线程安全,以便多个线程可以以线程安全的方式写入日志消息。我有一个锁对象,一次只允许一个线程写入。

同样在同一个应用程序中,我有一个GlobalExceptionHandler 类,它处理所有预期和意外的异常。异常的处理就是记录在一个文件中。所以,GlobalExceptionHandler 最终会调用FileLogger Log 方法来登录到文件。在代码方面可以显示为:

class FileLogger 

  ...

  public void Log(string logOrigin, string message, LogLevel logLevel) 
    //some code
    lock (logWriteLock) 
        try 
          using (var logFileStream = File.Open(logFilePath, FileMode.Append, FileAccess.Write, FileShare.Read)) 
            logFileStream.Write(messageBytes, 0, messageBytes.Length);
            logFileStream.Flush();
          
         catch (Exception ex)  
          globalExceptionHandler.HandleException(ex);
        
      
  



class GlobalExceptionHandler 

  public void HandleException(Exception ex) 
    //some code
    fileLogger.Log(...);
  

我的理解:

logWriteLock被线程获取,然后尝试打开文件并写入。快乐的场景会很好,但如果在尝试写入时出现异常,则控件将转到HandleException 方法,该方法将由同一线程执行。HandleException 将再次调用Log。由于线程已经拥有锁,它可以重新进入然后重新尝试写入文件。这将继续下去。

我的理解正确吗?还是会在我们到达globalExceptionHandler.HandleException(ex) 行时立即释放锁(因为我们已经到达临界区的末尾并且方法HandleException 没有显式锁定logWriteLock)?

我有一种直觉,我有循环引用并且会发生死锁。

此外,如果出现死锁,那么可能的解决方案是什么。我们是否需要一个额外的文件来记录 FileLogger 中的异常(我认为这不是一个好主意,因为我们会导致不必要的设计复杂性)?

【问题讨论】:

这里的术语有些偏离,但你的“直觉”是对的。您可能会陷入“无限”循环。您可以做的是通过 globalExceptionHandler 处理这个特定的异常not。但我建议你宁愿做的不是重新发明***。使用日志框架。 @Fildor 是的,我完全同意不重新发明***,但我受到限制,不能使用。此外,不通过 globalExceptionHandler 处理这一特定异常也无法达到将异常处理集中在一个位置的目的。 你不能同时拥有 :( 让全局处理程序处理它绝对是no有意义的。 Log 方法不应该做的是抛出异常,或者长时间阻塞调用者。您当前的方法似乎注定要两者兼得! 【参考方案1】:

或者是不是一打线就释放锁 globalExceptionHandler.HandleException(ex) (因为我们已经走到了尽头 临界区和方法 HandleException 没有明确 锁定 logWriteLock)?

您仍在锁定部分中,从锁定部分调用方法时进入的深度无关紧要。

因此,您将在持有锁的同时永远在里面循环。 当日志记录失败时,没有理由尝试记录异常,因为它也可能会失败。因此,要么使用另一种记录器,要么发送通知,以便在发生此类问题时做出反应。

【讨论】:

以上是关于在以下情况下是不是存在死锁,有啥解决方案可以防止它?的主要内容,如果未能解决你的问题,请参考以下文章

解决库存扣减及订单创建时防止并发死锁的问题

用java多线程编写哲学家就餐程序 利用多线程技术编写哲学家就餐程序,使之在运行时能演示产生死锁的情况,

mysql 死锁:如何解决mysql死锁

如果通过 Mongoose 在 Mongodb 的另一个文档中存在引用,有啥更好的方法可以防止文档被删除?

使用自引用外键的死锁

Python中死锁的形成示例及死锁情况的防止