C# - 为啥在使用 ReaderWriterLockSlim 时出现 LockRecursionException?
Posted
技术标签:
【中文标题】C# - 为啥在使用 ReaderWriterLockSlim 时出现 LockRecursionException?【英文标题】:C# - Why I get LockRecursionException when using ReaderWriterLockSlim?C# - 为什么在使用 ReaderWriterLockSlim 时出现 LockRecursionException? 【发布时间】:2020-08-18 21:33:28 【问题描述】:我正在开发一个多线程程序。我正在尝试使用两种类型的日志创建一个简单的日志记录系统:“INFO”和“ERROR”。 我创建了一个名为“Logger”的类和两个静态方法:Info 和 Error。我还创建了一个静态 ReadWriterLockSlim,因此一次只有一个线程可以写入日志文件。
日志记录工作了一段时间,但几分钟后我得到了这个异常:
System.Threading.LockRecursionException: 'Recursive write lock acquisitions not allowed in this mode.'
这是 Logger 类的代码:
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
方法中,您进入了写锁,但再也不会退出它。当同一个线程尝试进入Info
或Error
并再次获取锁时,您将得到该异常。您需要确保始终在获取锁后释放锁(最好使用 try/catch,以防写入消息引发异常)
另外,既然你从来没有读过,那么有一个读/写锁的原因是什么?这是一种专门的锁,它允许同时一个读取器或多个写入器。看起来您不能同时拥有多个编写器,因此您没有使用锁。从您发布的代码中,您可以使用简单的lock
statement
与Error
不释放锁一样,这两种方法都没有使用try-finally
来确保在整个写入日志文件时抛出异常时释放锁。如果在写入日志条目时随机发生 I/O 异常,您会泄漏锁并导致同样的问题。
@canton7 是的,我认为它解决了它。我的错。
@MartinCostello 谢谢马丁。你能告诉我一个我应该如何使用 try-finally 的例子吗?我还接受了 canton7 的建议,并将读取器/写入器锁更改为简单的 lock() 语句。你将如何使用 try-finally 和 lock() 语句?谢谢大家!
【参考方案1】:
您的问题出在您的 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;
也就是说,读/写锁是一种专用锁,它允许单个写入者或多个读取者同时访问资源。您没有任何读者,因此使用读/写锁没有意义。只需使用普通锁:
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;
【讨论】:
以上是关于C# - 为啥在使用 ReaderWriterLockSlim 时出现 LockRecursionException?的主要内容,如果未能解决你的问题,请参考以下文章