在以下情况下是否存在僵局,如何解决该僵局?

时间:2020-06-02 08:59:28

标签: c# multithreading logging thread-safety locking

我有一个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将再次调用{{1 }}。由于线程已经具有锁,因此它可以重新输入然后重新尝试写入文件。这将继续下去。

我的理解正确吗?还是在到达Log行时立即释放锁定(当我们到达关键部分的末尾并且方法globalExceptionHandler.HandleException(ex)未明确锁定HandleException时)?

我有种直觉,认为自己有循环引用,并且会发生死锁。

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

1 个答案:

答案 0 :(得分:3)

或者在我们上线后立即释放锁 globalExceptionHandler.HandleException(ex)(因为我们已经结束了 关键部分的内容,而方法HandleException并未明确 锁定logWriteLock)?

您仍然处于锁定部分,而从锁定部分调用方法时所获得的深度无关紧要。

因此,按住锁时,您将永远循环进入内部。

当记录失败时,没有理由尝试记录异常,因为它也可能会失败。因此,请使用其他记录器或发送通知,以便您在发生此类问题时能够做出反应。