在以下情况下是不是存在死锁,有啥解决方案可以防止它?
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多线程编写哲学家就餐程序 利用多线程技术编写哲学家就餐程序,使之在运行时能演示产生死锁的情况,