Zmagam się z problemem, który ostatnio pojawił się w prostej klasie logtofile, którą napisałem.Zmiana ciągu znaków na const łamie moją klasę rejestratora
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
namespace Assets.Code
{
class TimingLogger
{
public static readonly TimingLogger Logger = new TimingLogger();
private static readonly string path = "C:\\Logs\\TimingLog.txt";
private readonly Mutex mutex = new Mutex(false, path);
private StreamWriter writer;
private readonly Queue<string> queue = new Queue<string>();
private bool isRunning;
private readonly object obj = new object();
private TimingLogger()
{
}
public void CheckPath()
{
if (!File.Exists(path))
{
File.Create(path);
}
}
public void Run()
{
isRunning = true;
while (isRunning)
{
lock (obj)
{
while (queue.Count <= 0)
{
Monitor.Wait(obj);
}
Log(queue.Dequeue());
}
}
}
public void Log(string line)
{
try
{
mutex.WaitOne();
writer = File.AppendText(path);
writer.WriteLine(line);
writer.Close();
}
catch (Exception)
{
//throw;
}
finally
{
mutex.ReleaseMutex();
}
}
public void Enqueue(string line)
{
lock (obj)
{
queue.Enqueue(line);
Monitor.Pulse(obj);
}
}
public void Stop()
{
isRunning = false;
}
}
}
Ta klasa działała dobrze do niedawna, gdy zauważyłem, że mój plik dziennika nie zawierał danych, które oczekiwałem. Co dziwne, nie zmieniłem żadnej funkcjonalności klasy. Porównując starą, działającą wersję z moją nową, jedyną różnicą było to, że niektóre z moich pól zostały utworzone private
i readonly
. Poza tym string path
został zmieniony na const
. I do mojego kompletnego oszołomienia, zmiana tego z powrotem na readonly
naprawiła problem, który miałem.
Moje pytanie brzmi: jak to możliwe? O ile mi wiadomo, nie powinno być funkcjonalnie żadnej różnicy między readonly i const w tej sytuacji.
Podczas debugowania zmiana w zachowaniu jest znaczna, szczególnie w metodzie Run()
. To, co się stanie, to: po wywołaniu Log(queue.Dequeue());
, wątek opuści instrukcję lock
i ponownie przejdzie przez pętlę while (isRunning)
. Wydaje się to dość oczywiste, prawda? Jednak po zmianie string path
na const
i ponownym debugowaniu, Log(queue.Dequeue());
jest przekazywany raz, a pojedyncza instrukcja znajduje się w pliku dziennika, po czym po prostu nie robi nic więcej. Nie przechodzi ponownie obok while (isRunning)
i wydaje się, że nie opuszcza bloku lock (obj)
. Wątek programu rejestrującego wydaje się po prostu wyłączać lub wstrzymywać po pomyślnym wywołaniu.
Faktycznie odrzucenie wyjątku w metodzie Log
nie ma znaczenia, nie są zgłaszane żadne wyjątki, ponieważ samo rejestrowanie działa poprawnie.
Należy wspomnieć, że używam tego kodu z Unity3D 5, który używa Mono. Wciąż jednak ta drastyczna zmiana w zachowaniu przez tak małą edycję wydaje mi się niemożliwa. Czy ktoś może wyjaśnić, dlaczego tak się dzieje?
Dzięki!
myślałem, że to trochę za dużo kod aby umieścić wewnątrz treści wiadomości, ale w porządku, Dodałem to. – David
To znacznie lepiej niż link, który może zniknąć i sprawić, że pytanie będzie niezrozumiałe w późniejszym czasie. Pisanie rejestratora to trudna sprawa, która została już rozwiązana. Czy nie byłoby lepiej użyć istniejącego rozwiązania, takiego jak [nLog] (http://nlog-project.org/)? – spender
Zabawne, że powinieneś o tym wspomnieć, spróbowałem nLog, ale napotkałem pewne problemy z uruchomieniem go z Unity3D 5. Po prostu powtórzę, mój logger działa dobrze teraz, gdy już zlokalizowałem i naprawiłem problem. Po prostu nie rozumiem problemu. – David