【发布时间】: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方法不应该做的是抛出异常,或者长时间阻塞调用者。您当前的方法似乎注定要两者兼得!
标签: c# multithreading logging thread-safety locking