为什么在C#中使用ReadWriteLock时会出现文件共享异常?

时间:2018-09-21 15:48:55

标签: c# file logging locking

这是我最近一次运行的输出,其中我并行索引数据库表的10列。写入日志文件的代码如下。

INFO: Status Indexing column Master_State as index I5
INFO: Status Indexing column Master_current0 as index I4
INFO: Status Indexing column Master_qlevel as index I3
INFO: Status Indexing column Master_received_Day as index I1
Got sharing exception with lock!
INFO: Status Indexing column Master_customer as index I7
Waiting on file
INFO: Status Indexing column Master_received_Year as index I8
INFO: Status Indexing column Master_received_Month as index I9
Waiting on file
INFO: Status Indexing column seq_no as index I10

这里是编写消息“带锁的共享异常!”的代码。

private static void WriteToPath(object msg, string logPath)
{
    while (true)
    {
        try
        { // These first two lines are to handle different users and/or
          // applications that log to the same log file.
          // If the File.Open fails because the file is in use, Exception
          // then wait and try again.
          //
            FileStream writer = File.Open(logPath, FileMode.Append);
            writer.Close();

            locker.AcquireWriterLock(writerTimeouts);
            try
            {
                Interlocked.Increment(ref writes);
                try
                {
                    using (var logWriter = File.AppendText(logPath))
                    {
                        logWriter.WriteLine((string)msg);
                    }
                    break; // break out of the while loop as we're done.
                }
                catch
                { // Here I write out the fact that I got an exception
                  // but not the long details about file sharing exception.
                    Console.Out.WriteLine("Got sharing exception with lock!");
                }
            }
            finally
            {
                if (locker.IsWriterLockHeld)
                    locker.ReleaseWriterLock();
            }
        }
        catch (Exception)
        {
            Interlocked.Increment(ref writerTimeouts);
            Console.Out.WriteLine("Waiting on file");
            Thread.Sleep(5000);
        }
    }
}

此WriteToPath的调用如下所示:

public static void Log(string dir, string pgm, string errorLevel, string msgType, string details)
{
    string line = null;
    if (details != null)
    {
        line = FormatLogMessage(pgm, errorLevel, msgType, details);
    }
    else
    {
        line = FormatLogMessage(pgm, "INFO", "End", BuildInfo.ApplicationName);
    }
    ThreadPool.QueueUserWorkItem(WriteWithLock, line);
}

private static void WriteWithLock(object msg)
{
    string logPath = _cfg.getLogDirectory() + GetLogFileName();
    WriteToPath(msg, logPath);
}

这是使用

并行运行的一系列应用程序的一部分
  ProcessStartInfo info = new ProcessStartInfo();
            info.FileName = batchFile;
            info.Arguments = argList;
            Process.Start(info);

因此,每个应用程序都独立运行。因此,它们没有共享或通用锁,但每个应用程序都有一个。这些应用程序通常运行大约10个线程,所有线程都在执行类似的工作,例如为数据库的列建立索引,或将来自10个不同文件的行插入数据库等。对于这些应用程序,上述锁定机制应该起作用。但是,我开始等待存档,有时会遇到“共享异常”。它对并行线程有效,并且我不会丢失任何数据,但是为什么会发生呢?另外,这对单独的应用程序有用吗?

似乎Windows 10应该具有类似     任何人都可以调用的System.Logging.LogToFile(path,message),系统将管理任何冲突。我找不到这样的东西,但是肯定会很好!

在此方面的协助将不胜感激。

1 个答案:

答案 0 :(得分:0)

这里是我所用的精简版本,互斥体应该做您想要的事情,至少这对我没有问题:

public sealed class GlobalLogger : IDisposable
{
    private static GlobalLogger Logger;
    private readonly Mutex _lock;
    private string _activityLogPath;
    private const string ActivityLogFileName =  @"activity.log";

    private GlobalLogger()
    {
        _lock = new Mutex(false, ActivityLogFileName);          
    }

    /// <summary> Finds the root path of the MSD, sets up log file. </summary>
    /// <returns>Drive info, or null if not found</returns>
    public static void Init()
    {
        if (null == Logger)
        {
            Logger = new GlobalLogger();
        }

        if (string.IsNullOrEmpty(_activityLogPath))
        {
            Logger._activityLogPath = ActivityLogFileName;
        }
    }

    //
    // Debug 
    //
    public static void DebugWriteLineInfo(object sender, string format, params object[] args)
    {
        DebugWriteMessage(sender, "I", true, format, args);
    }

    public static void DebugWriteLineWarning(object sender, string format, params object[] args)
    {
        DebugWriteMessage(sender, "W", true, format, args);
    }

    public static void DebugWriteLineError(object sender, string format, params object[] args)
    {
        DebugWriteMessage(sender, "E", true, format, args);
    }

    private static void DebugWriteMessage(object sender, string severity, bool writeLine, string format, params object[] args)
    {
        if (writeLine)
        {
            Debug.WriteLine(format);
        }
        else
        {
            Debug.Write(format);
        }     
    }

    //
    // Logging
    //
    private static void Log(string logType, string severity, object sender, string format, params object[] args)
    {
        Init();

        if (Logger._lock.WaitOne(250))
        {
            try
            {
                using (StreamWriter sw = new StreamWriter(Logger._activityLogPath, true))
                {
                    if (logType != "RAW")
                    {
                        sw.Write("{0} {1} {2} ",
                            DateTime.Now,
                            logType,
                            severity);
                    }

                    sw.WriteLine(format, args);
                }
            }
            finally
            {
                Logger._lock.ReleaseMutex();
            }
        }
    }

    public static void LogActivityInformation(object sender, string format, params object[] args)
    {
        Log("ACT", "I", sender, format, args);  
    }

    public static void LogActivityWarning(object sender, string format, params object[] args)
    {
        Log("ACT", "W", sender, format, args);  
    }

    public static void LogActivityError(object sender, string format, params object[] args)
    {
        Log("ACT", "E", sender, format, args);  
    }
    public static void LogApplicationInformation(object sender, string format, params object[] args)
    {
        Log("APP", "I", sender, format, args);  
    }

    public static void LogApplicationWarning(object sender, string format, params object[] args)
    {
        Log("APP", "W", sender, format, args);  
    }

    public static void LogApplicationError(object sender, string format, params object[] args)
    {
        Log("APP", "E", sender, format, args);  
    }

    public static void LogSystemInformation(object sender, string format, params object[] args)
    {
        Log("SYS", "I", sender, format, args);  
    }

    public static void LogSystemWarning(object sender, string format, params object[] args)
    {
        Log("SYS", "W", sender, format, args);  
    }

    public static void LogSystemError(object sender, string format, params object[] args)
    {
        Log("SYS", "E", sender, format, args);  
    }

    public static void LogRaw(object sender, string format, params object[] args)
    {
        Log("RAW", string.Empty, sender, format, args);
    }

    public void Dispose()
    {
        if (null != _lock)
        {
            _lock.Close();
        }
    }
}    

大多数时候我只是这样记录:GlobalLogger.LogApplicationInformation(this,“信息消息:{0}”,randomTypeArg);

相关问题