文件被其他线程占用

本文关键字:线程 其他 文件 | 更新日期: 2023-09-27 18:09:50

我编写了这个静态日志类来记录多个线程期间的所有状态。有时我得到一个异常,说日志文件(程序正在写)被占用了。似乎其他线程在同一时间写文件。我把所有这些工作调用到UI线程,以避免这种异常,但它仍然发生。任何建议吗?谢谢。

顺便说一句,我知道我可以使用锁(mLog)来避免这个问题,但我仍然想知道为什么会发生这种情况,UI线程不应该运行2日志。同时更新elog日志管理系统,对吗?

public partial class LogForm : Form
{
    private StringBuilder mLog;
    public LogForm()
    {
        InitializeComponent();
        mLog = new StringBuilder();
    }
    public void Write(string msg, bool save)
    {
        mLog.Insert(0, msg + "'r'n'r'n" + "-----------------------------------------------------------------------" + "'r'n'r'n");
        if (save)
        {
            SaveFile();
        }
    }
    private void SaveFile()
    {
        FileStream file;
        file = new FileStream(Application.StartupPath + @"'LOG.txt", FileMode.Create);
        StreamWriter sw = new StreamWriter(file);
        sw.Write(mLog.ToString());
        sw.Close();
        file.Close();
    }

}
public static class Log
{
    private delegate void mUIInvoke(string msg, bool save);
    private static LogForm mLogForm = new LogForm();
    public static void Write(string msg, bool save)
    {
        msg += "'r'nTIME:" + DateTime.Now.ToShortDateString() + "  " + DateTime.Now.ToShortTimeString();
        if (mLogForm.InvokeRequired)
        {
            mUIInvoke invoke = new mUIInvoke(UpdateLog);
            mLogForm.BeginInvoke(invoke, new object[] { msg, save });
        }
        else
        {
            UpdateLog(msg, save);
        }
    }

    private static void UpdateLog(string msg, bool save)
    {
        mLogForm.Write(msg, save);
    }
}

文件被其他线程占用

对于实现日志记录来说,这绝对不是一个优雅的方法,因为您的类中有多个线程。如果你想要一个更好的设计,你的日志内容必须从表单类中移出,因为日志记录是独立的,线程不应该访问"表单"来"日志"使其有意义。

有两种选择。

  1. 选择经过测试和验证的日志框架,如log4net或NLog

  2. 使这个日志类独立,并创建一个logger类的实例(主要是一个单例,尽管我反对单例类),并在多个线程之间共享它。文件管理、日志功能等必须分开管理。所有的操作都必须使用线程同步机制(如互斥锁)来保护。有几种方法可以实现日志框架。这完全取决于你真正需要多少!

除非它不是一个大问题或用于学习目的,否则我建议您使用现有的日志框架,特别是在与生产质量代码一起使用时。

这不是UI线程的问题。问题(主要)在SaveFile方法中。如果两个不同的线程试图访问这个方法,一个线程可能会发现文件仍在被另一个线程使用。一个简单的锁就可以解决这个问题。

假设线程A调用mLogForm.Write它进入方法并不间断地到达SaveFile方法,它打开文件流,但此时被中断,操作系统决定运行线程B线程B运行并到达相同的SaveFile,发现文件被前一个线程锁定

这里有一个理论:您的日志表单是通过静态变量访问的。这个变量在Log类的第一次访问时初始化,这个第一次访问可以在非ui线程中进行。因此,您的表单可以在非ui线程上创建,这可能会导致您遇到的问题。

我和我的一个朋友一起解决了这个问题。这实际上是因为mLogForm之前从未被展示过。调用invokerrequired。如果没有显示,就永远不会有mLogForm的句柄。没有句柄,您将无法调用mLogForm。以正确的方式调用。这意味着即使其他线程调用Log,它也会返回false。写然后我有很多线程运行UpdateLog方法,导致这个问题。为了确保可以对未显示的表单使用invoke,请在创建此表单时使用CreateHandle()。谢谢。