Почему я получаю исключения при совместном использовании файлов при использовании ReadWriteLock в C #? - PullRequest
0 голосов
/ 21 сентября 2018

Вот вывод из моего последнего прогона, где я параллельно индексирую 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 (путь, сообщение), который любой может вызвать, и система будет управлять любыми конфликтами.Я не могу найти ничего подобного, но это было бы неплохо!

Помощь в этом была бы признательна.

1 Ответ

0 голосов
/ 21 сентября 2018

Вот урезанная версия того, что я использую, Mutex должен делать то, что вы ищете, по крайней мере, это сработало для меня без проблем:

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 (это, "информационное сообщение: {0}", randomTypeArg);

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...