.NET 2.0: File.AppendAllText (...) - потокобезопасная реализация - PullRequest
11 голосов
/ 26 января 2011

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

internal static class Logging
{
    private static object threadlock;

    static Logging()
    {
        threadlock = new object(); 
    }

    internal static void WriteLog(string message)
    {
        try
        {
            lock (threadlock)
            {
                File.AppendAllText(@"C:\logfile.log", message);
            }
        }
        catch
        {
            ...handle logging errors...
        }
    }
}

Требуется ли lock около File.AppendAllText(...) или метод сам по себе является поточно-ориентированным в своей собственной реализации?

Поиск информации об этом дает много противоречивой информации, некоторые говорят «да», некоторые говорят «нет». MSDN ничего не говорит.

Ответы [ 3 ]

16 голосов
/ 26 января 2011

File.AppendAllText собирается получить эксклюзивную блокировку записи в файле журнала, что приведет к тому, что любой параллельный поток, пытающийся получить доступ к файлу, вызовет исключение. Так что да, вам нужен статический объект блокировки, чтобы предотвратить одновременную запись в файл журнала несколькими потоками и получение IOException.

Если это будет проблемой, я действительно рекомендую войти в таблицу базы данных, которая лучше справится с одновременной записью журналов.

В качестве альтернативы, вы можете использовать TextWriterTraceListener, который является поточно-ориентированным (ну, это сделает блокировку за вас; я бы лучше написал как можно меньше своего собственного многопоточного кода).

2 голосов
/ 25 сентября 2017

Тестирование параллельной записи показывает, что вы получите исключение System.IO.IOException, если вы закомментируете оператор блокировки.

[Test]
public void Answer_Question()
{
    var ex = Assert.Throws<AggregateException>(() => Parallel.Invoke(
        () => Logging.WriteLog("abc"),
        () => Logging.WriteLog("123")
    ));

    // System.IO.IOException: The process cannot access the file 'C:\Logs\thread-safety-test.txt' because it is being used by another process.
    Console.Write(ex);
}
0 голосов
/ 26 января 2011

Потокобезопасен в том смысле, что он открывает файл с разделением «Чтение», поэтому при условии, что ваша файловая система учитывает блокировки файлов, только один поток будет разрешен для записи в файл за один раз.Однако другие потоки могут получить грязное чтение, если они пытаются прочитать тот же файл.

...