C# - 为什么在使用 ReaderWriterLockSlim 时出现 LockRecursionException?

C# - Why I get LockRecursionException when using ReaderWriterLockSlim?

我正在开发一个多线程程序。我正在尝试使用两种类型的日志创建一个 简单日志系统 :'INFO' 和 'ERROR'。 我创建了一个名为 'Logger' 的 class 和两个静态方法:Info 和 Error。我还创建了一个静态 ReadWriterLockSlim,因此一次只有一个线程可以写入日志文件。

日志记录工作了一段时间,但几分钟后我得到了这个异常:

System.Threading.LockRecursionException: 'Recursive write lock acquisitions not allowed in this mode.'

这是记录器 class 代码:

public class Logger
{
    const string filePath = "Log.txt";
    static private ReaderWriterLockSlim writeLock = new ReaderWriterLockSlim();
    public static string Info(string log)
    {
        StringBuilder sb = new StringBuilder();
        string logMessage = DateTime.Now.ToString() + " | INFO | " + log;
        writeLock.EnterWriteLock();
        using (StreamWriter writetext = File.AppendText(filePath))
        {
            writetext.WriteLine(logMessage);
            Console.WriteLine(logMessage);
        }
        writeLock.ExitWriteLock();
        return logMessage;
    }

    public static string Error(string log)
    {
        StringBuilder sb = new StringBuilder();
        string logMessage = DateTime.Now.ToString() + " | ERROR | " + log;
        writeLock.EnterWriteLock();
        using (StreamWriter writetext = File.AppendText(filePath))
        {
            writetext.WriteLine(logMessage);
            Console.WriteLine(logMessage);
        }
        return logMessage;
    }

}

希望有人能帮助我理解我做错了什么以及如何解决它。 提前谢谢大家。

您的问题出在您的 Error 方法中:它获取了锁,但没有再次释放它。

另外,你真的应该在获取锁时使用 try/finally。这样可以确保如果在写日志消息时抛出异常,锁总是被释放:

public static string Error(string log)
{
    StringBuilder sb = new StringBuilder();
    string logMessage = DateTime.Now.ToString() + " | ERROR | " + log;
    writeLock.EnterWriteLock();
    try
    {
        using (StreamWriter writetext = File.AppendText(filePath))
        {
            writetext.WriteLine(logMessage);
            Console.WriteLine(logMessage);
        }
    }
    finally
    {
        writeLock.ExitWriteLock();
    }
    return logMessage;
}

也就是说,read/write 锁是一种专用锁,允许单个写入者或多个读取者同时访问资源。您没有任何读者,因此没有必要使用 read/write 锁。只需使用普通锁:

public class Logger
{
    const string filePath = "Log.txt";
    private static readonly object lockObject = new object();
    public static string Info(string log)
    {
        StringBuilder sb = new StringBuilder();
        string logMessage = DateTime.Now.ToString() + " | INFO | " + log;
        lock (lockObject)
        {
            using (StreamWriter writetext = File.AppendText(filePath))
            {
                writetext.WriteLine(logMessage);
                Console.WriteLine(logMessage);
            }
        }
        return logMessage;
    }

    public static string Error(string log)
    {
        StringBuilder sb = new StringBuilder();
        string logMessage = DateTime.Now.ToString() + " | ERROR | " + log;
        lock (lockObject)
        {
            using (StreamWriter writetext = File.AppendText(filePath))
            {
                writetext.WriteLine(logMessage);
                Console.WriteLine(logMessage);
            }
        }
        return logMessage;
    }
}