我试图创建一个线程安全的方法。
有没有人看到以下代码出现任何并发问题?
对我来说似乎很好,虽然我找不到一种方法来测试这种方法的并发性。任何帮助都会受到赞赏。
//static locker for thread synchronization
private static readonly System.Object _object3 = new System.Object();
//this method needs to be thread-safe
public static void LogToTextFile(string logMessage, LogLevel logType)
{
//make sure only one thread executes this file writing code at a time
lock (_object3)
{
using (StreamWriter w = File.AppendText(@"c:\logs\log1.txt");
{
w.WriteLine("\r\n{0} logged at {1} {2} : {3}", logType.ToString().ToUpper(), DateTime.Now.ToLongTimeString(), DateTime.Now.ToLongDateString(), logMessage);
}
}
}
答案 0 :(得分:3)
此代码没有并发问题,因为由于lock语句,您只允许单个线程写入文件。
答案 1 :(得分:1)
考虑到lock
围绕一个适当范围的对象,我发现你的代码没有并发问题。
但是,正如评论中提到的millimoose,您有潜在的性能问题。如果两个线程同时尝试LogToTextFile
,则一个将首先获取锁定,另一个将在文件打开,写入然后关闭时阻止。这可能是不可接受的,这取决于你的线程在做什么。
如果我提到的是一个问题,你将不得不实现一个更复杂的线程安全记录器。通常会有一个快速写入日志事件的队列。然后有另一个线程定期唤醒,并将队列清空到磁盘上的文件。队列中的所有操作都是通过锁完成的。
答案 2 :(得分:1)
另一个可能更好的解决方案可能是打开文件,并使用同步TextWriter
来执行写入。 TextWriter.Synchronized
围绕TextWriter
:
对返回的包装器的所有写操作都是线程安全的。您可以调用此方法以确保一次只有一个线程可以执行返回的TextWriter实例上的方法。
这是一个简单的实现。请注意,这尚未经过测试。
public static class MyLogger
{
private static TextWriter s_writer;
// Not thread-safe. Call this before other threads are allowed to call Log.
public void Open(string filename) {
s_writer = TextWriter.Synchronized( File.AppendText(filename) );
}
// Also not thread-safe.
public void Close() {
s_writer.Dispose();
}
// Thread-safe.
public void Log(string logMessage, LogLevel logType) {
s_writer.WriteLine("\r\n{0} logged at {1} {2} : {3}",
logType.ToString().ToUpper(), DateTime.Now.ToLongTimeString(),
DateTime.Now.ToLongDateString(), logMessage);
}
}
答案 3 :(得分:1)
此特定功能中没有并发问题。 lock
语句将适当地控制对内部代码的访问。
然而,访问@"c:\logs\log1.txt"
仍然存在潜在的并发问题。应用程序的另一部分或同一台机器上的另一个进程可能会尝试在代码的同时写入文件。因此,即使使用此锁,StreamWriter
代码也可能会失败。
无法解决此类并发问题。文件系统是您无法保护的共享资源。相反,您的代码需要接受文件系统访问可能失败并正确处理该后果。
通常在处理日志记录功能时,我使用try / catch
包装文件系统访问权限并吞下发生的任何异常。否则,您将面临关闭应用程序的日志记录功能失败的风险。对于您的方案,这可能是也可能不可接受。