The test below proves that using TextWriterTraceListener
is thread safe if used via Trace
object. Tested in .net6
First, the code from the library, where we see that listener is locked if it is not a thread safe listener.
foreach (TraceListener listener in TraceInternal.Listeners)
{
if (!listener.IsThreadSafe)
{
lock (listener)
{
listener.TraceEvent(eventCache, TraceInternal.AppName, eventType, id, format, args);
if (TraceInternal.AutoFlush)
listener.Flush();
}
}
else
{
listener.TraceEvent(eventCache, TraceInternal.AppName, eventType, id, format, args);
if (TraceInternal.AutoFlush)
listener.Flush();
}
}
Unit test
Trace.Listeners.Clear();
Trace.Listeners.Add(new TextWriterTraceListener("C:\\temp\\TEMP-\\mylog.log"));
var rand = new Random();
var sw = Stopwatch.StartNew();
var t1 = Task.Run(() => Write(sw, "Thread#1", rand));
var t2 = Task.Run(() => Write(sw, "Thread#2", rand));
var t3 = Task.Run(() => Write(sw, "Thread#3", rand));
var t4 = Task.Run(() => Write(sw, "Thread#4", rand));
var t5 = Task.Run(() => Write(sw, "Thread#5", rand));
Task.WaitAll(t1, t2, t3, t4, t5);
Trace.Close();
//-----------
static void Write(Stopwatch sw, string threadName, Random rand)
{
while(sw.Elapsed.TotalSeconds < 30)
{
int ms = rand.Next(10, 20);
//System.Threading.Thread.Sleep(ms); -- no slow down process
Trace.TraceInformation("Thread '{0}' @ {1}", threadName, ms);
}
}
And the file
TestCode Information: 0 : Thread 'Thread#2' @ 14
TestCode Information: 0 : Thread 'Thread#1' @ 18
TestCode Information: 0 : Thread 'Thread#2' @ 15
TestCode Information: 0 : Thread 'Thread#1' @ 18
TestCode Information: 0 : Thread 'Thread#1' @ 13
TestCode Information: 0 : Thread 'Thread#2' @ 12
TestCode Information: 0 : Thread 'Thread#1' @ 12
TestCode Information: 0 : Thread 'Thread#2' @ 14
TestCode Information: 0 : Thread 'Thread#1' @ 12
TestCode Information: 0 : Thread 'Thread#1' @ 10
TestCode Information: 0 : Thread 'Thread#2' @ 11
TestCode Information: 0 : Thread 'Thread#1' @ 16
TestCode Information: 0 : Thread 'Thread#2' @ 16
TestCode Information: 0 : Thread 'Thread#1' @ 12
TestCode Information: 0 : Thread 'Thread#2' @ 14
TestCode Information: 0 : Thread 'Thread#1' @ 14
TestCode Information: 0 : Thread 'Thread#2' @ 18
TestCode Information: 0 : Thread 'Thread#1' @ 12
TestCode Information: 0 : Thread 'Thread#2' @ 12
TestCode Information: 0 : Thread 'Thread#2' @ 16
TestCode Information: 0 : Thread 'Thread#3' @ 18
TestCode Information: 0 : Thread 'Thread#1' @ 18
TestCode Information: 0 : Thread 'Thread#1' @ 11
TestCode Information: 0 : Thread 'Thread#1' @ 13
TestCode Information: 0 : Thread 'Thread#3' @ 19
TestCode Information: 0 : Thread 'Thread#2' @ 19
TestCode Information: 0 : Thread 'Thread#1' @ 10
TestCode Information: 0 : Thread 'Thread#3' @ 14
TestCode Information: 0 : Thread 'Thread#1' @ 10