【问题标题】:Timers, Files and race conditions?计时器、文件和竞争条件?
【发布时间】:2023-08-11 06:36:01
【问题描述】:

您好,感谢您的帮助。 这次我对正在编写的程序(C#)有一个奇怪的问题,想听听你的建议。 我正在编写一个普通程序(不是多线程),然后添加了一个计时器(System.Timers.Timer)

我还使用 StreamWriter 写入文件。我是这样打开的

StreamWriter logStream=new StreamWriter(filename, true);

表示如果文件存在,则追加,如果不存在,则创建。

后来我这样写到文件里

logStream.WriteLine(message);

但是,我从 主函数和计时器调用的函数写入流。

问题症状

当我刷新或写入流说“无法访问已关闭的文件”和其他时候“无法访问已关闭的 TextWriter...(什么是“TextWriter”?) /p>

但奇怪的是,文件一直在写入而没有问题。 (即使是“无法访问关闭的文件”消息也写在假定的关闭文件中)

我不熟悉 Timer 的内部工作原理。 (我想它运行一个单独的线程?)

我的问题是

是否可以从多个线程中使用 StreamWriter? (在这种情况下是主要的和定时器的) 是否有可能发生竞争条件或类似的问题?


还有一件事:我犯了一个逻辑错误,每次我想在上面写字时都关闭并重新打开文件。是的,这是一个错误,我应该纠正它。但也许如果我纠正这个错误,我上面描述的错误就会消失,掩盖一个更严重的缺陷。

我的怀疑是,由于我每次在上面写文件时都会关闭和打开文件,可能两个线程都试图在错误的时间访问它们

任何帮助将不胜感激

【问题讨论】:

  • 对于您的一个问题:StreamWriter 是特定的 TextWriter。
  • 您是否正在尝试创建日志记录实现?为什么不使用 .NET 的内置诊断 API 或 log4net 之类的日志库?日志库必须接受来自多个线程的日志请求,同时正确写入所有条目而不会损坏日志文件。

标签: c# timer streamwriter


【解决方案1】:

在这种情况下关闭和打开您的文件会产生您怀疑的竞争条件。您不能保持流打开并将对象传递给线程,因为如果您从不同的线程调用,您最终可能会遇到类似的问题。您最好的解决方案仍然是使用一种线程安全的方法,该方法将写入您发送给它的内容。

这些方法是静态的,因为锁必须可以从类的所有实例中访问。

private static ReaderWriterLockSlim readerWriterLockSlim = new ReaderWriterLockSlim();

public static void AppendToFile(string path, string text) 
{
    // Set to locked (other thread will freeze here until object is unlocked
    readerWriterLockSlim.EnterWriteLock();

    try
    {
        // Write that will append to the file
        using (StreamWriter sw = File.AppendText(path))
        {
            // append the text
            sw.WriteLine(text);
            sw.Close();
        }
    }
    finally
    {
        // Clear the lock
        readerWriterLockSlim.ExitWriteLock();
    }
}

【讨论】:

  • 更好的是,使用日志库。或者是一个 ActionBlock,它将来自多个线程的消息排队并使用简单的 writer 将它们一一写入