2011-01-26 11 views
10

jako ćwiczenie w ciekawości bardziej niż cokolwiek innego, należy rozważyć następującą prostą klasę rejestrowania:.NET 2.0: File.AppendAllText (...) - wątek bezpiecznego wdrożenia

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... 
     } 
    } 
} 

Czy lock potrzeba około File.AppendAllText(...) lub czy metoda z natury jest bezpieczna dla wątków przez własną implementację?

Wyszukiwanie informacji na ten temat daje dużo sprzecznych informacji, niektóre mówią tak, niektórzy twierdzą, że nie. MSDN nic nie mówi.

Odpowiedz

16

File.AppendAllText zamierza uzyskać wyłączną blokadę zapisu w pliku dziennika, co spowoduje, że dowolny wątek równoczesny będzie próbował uzyskać dostęp do pliku, aby wygenerować wyjątek. Tak, tak, potrzebujesz statycznego obiektu blokującego, aby zapobiec jednoczesnemu zapisywaniu w pliku dziennika wielu wątków i zwiększaniu wartości IOException.

Jeśli to będzie problem, naprawdę proponuję zalogować się do tabeli bazy danych, która będzie lepiej radzić sobie z równoczesnymi zapisami dziennika.

Alternatywnie, możesz użyć TextWriterTraceListener, który jest bezpieczny dla wątków (dobrze, zrobi to za ciebie, wolałbym napisać jak najmniej mojego własnego wielowątkowego kodu, jak to możliwe).

+1

Jest to sprzeczne. Jeśli File.AppendAllText ma wyłączną blokadę zapisu, dlaczego potrzebujesz osobnej blokady? – iheanyi

+4

Źle zrozumiałeś, to plik jest zablokowany do zapisu. Tak więc wszelkie inne wątki próbujące pisać w tym samym czasie otrzymają wyjątek. Aby temu zapobiec, musisz serializować zapisy, używając blokady w swoim programie. – Pradeep

+0

Nie marnuj cennych zasobów bazy danych do rejestrowania, jeśli używasz ciężkiej relacyjnej bazy danych, w przeciwnym razie, jeśli używasz bazy danych lite nosql, to nie jest źle, aby zalogować się do bazy danych. Użyj czegoś takiego jak dziennik zdarzeń systemu Windows, jeśli chcesz logować się lokalnie, ale nie pisz samemu do systemu plików. Ale dlaczego nie pisać nowego pliku na dziennik zamiast dodawać, jeśli chcesz być bezpieczny i bezpieczny? –

0

Jest bezpieczny dla wątków w tym sensie, że otwiera plik z udostępnianiem odczytu, więc zakładając, że twój system plików honoruje blokady plików, tylko jeden wątek będzie mógł zapisywać do pliku na raz. Inne wątki mogą jednak zabrudzić odczyty, jeśli próbują odczytać ten sam plik.

+7

I inne wątki będą zgłaszać wyjątki podczas próby zapisu. –

0

Testowanie zapisu równoległego pokazuje, że w przypadku komentowania wyciągu blokującego można uzyskać wyjątek 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); 
} 
Powiązane problemy