作为闲置好奇心的练习,请考虑以下简单的记录类:
internal static class Logging
{
private static object threadlock;
static Logging()
{
threadlock = new object();
}
internal static void WriteLog(string message)
{
try
{
lock (threadlock)
{
File.AppendAllText(@"C:\logfile.log", message);
}
}
catch
{
...handle logging errors...
}
}
}
lock
需要围绕File.AppendAllText(...)
,或者它自己的实现方法本身就是线程安全的吗?
搜索有关这方面的信息会产生很多相互矛盾的信息,有些人说是,有些人说不。 MSDN什么也没说。
答案 0 :(得分:16)
File.AppendAllText
将获取日志文件的独占写锁定,这将导致尝试访问该文件的任何并发线程抛出异常。所以,是的,您需要一个静态锁定对象来防止多个线程同时尝试写入日志文件并引发IOException
。
如果这是一个问题,我真的建议记录到数据库表,这样可以更好地处理并发日志编写器。
或者,您可以使用线程安全的TextWriterTraceListener
(好吧,它会为您执行锁定;我宁愿尽可能少地编写自己的多线程代码)。
答案 1 :(得分:2)
测试并行写入表明如果你要注释掉你的lock语句,你会得到一个System.IO.IOException。
[Test]
public void Answer_Question()
{
var ex = Assert.Throws<AggregateException>(() => Parallel.Invoke(
() => Logging.WriteLog("abc"),
() => Logging.WriteLog("123")
));
// System.IO.IOException: The process cannot access the file 'C:\Logs\thread-safety-test.txt' because it is being used by another process.
Console.Write(ex);
}
答案 2 :(得分:0)
在使用Read共享打开文件的意义上,它是线程安全的,因此假设您的文件系统遵循文件锁定,一次只允许一个线程写入该文件。但是,如果其他线程试图读取同一文件,则可能会出现脏读。