-Fixed MemoryTraceWriter thread safety

This commit is contained in:
James Newton-King
2017-04-30 17:06:31 +12:00
parent 275741ff09
commit 92653ae3f2
2 changed files with 83 additions and 13 deletions
@@ -27,6 +27,9 @@ using Newtonsoft.Json.Utilities.LinqBridge;
#else
using System.Linq;
#endif
#if !(NET20 || NET35 || NET40 || PORTABLE40 || PORTABLE) || DNXCORE50
using System.Threading.Tasks;
#endif
namespace Newtonsoft.Json.Tests.Serialization
@@ -317,6 +320,63 @@ Newtonsoft.Json Error: 0 : Error!
Assert.IsTrue(traceMessages.Last().EndsWith(" 1005"));
}
#if !(NET20 || NET35 || NET40 || PORTABLE40 || PORTABLE) || DNXCORE50
[Test]
public async Task MemoryTraceWriterThreadSafety_Trace()
{
List<Task> tasks = new List<Task>();
MemoryTraceWriter traceWriter = new MemoryTraceWriter();
for (int i = 0; i < 20; i++)
{
tasks.Add(Task.Run(() =>
{
for (int j = 0; j < 1005; j++)
{
traceWriter.Trace(TraceLevel.Verbose, (j + 1).ToString(CultureInfo.InvariantCulture), null);
}
}));
}
await Task.WhenAll(tasks);
IList<string> traceMessages = traceWriter.GetTraceMessages().ToList();
Assert.AreEqual(1000, traceMessages.Count);
}
[Test]
public async Task MemoryTraceWriterThreadSafety_ToString()
{
List<Task> tasks = new List<Task>();
MemoryTraceWriter traceWriter = new MemoryTraceWriter();
tasks.Add(Task.Run(() =>
{
for (int j = 0; j < 10005; j++)
{
traceWriter.Trace(TraceLevel.Verbose, (j + 1).ToString(CultureInfo.InvariantCulture), null);
}
}));
string s = null;
tasks.Add(Task.Run(() =>
{
for (int j = 0; j < 10005; j++)
{
s = traceWriter.ToString();
}
}));
await Task.WhenAll(tasks);
Assert.IsNotNull(s);
}
#endif
[Test]
public void Serialize()
{
@@ -13,6 +13,7 @@ namespace Newtonsoft.Json.Serialization
public class MemoryTraceWriter : ITraceWriter
{
private readonly Queue<string> _traceMessages;
private readonly object _lock;
/// <summary>
/// Gets the <see cref="TraceLevel"/> that will be used to filter the trace messages passed to the writer.
@@ -31,6 +32,7 @@ namespace Newtonsoft.Json.Serialization
{
LevelFilter = TraceLevel.Verbose;
_traceMessages = new Queue<string>();
_lock = new object();
}
/// <summary>
@@ -41,11 +43,6 @@ namespace Newtonsoft.Json.Serialization
/// <param name="ex">The trace exception. This parameter is optional.</param>
public void Trace(TraceLevel level, string message, Exception ex)
{
if (_traceMessages.Count >= 1000)
{
_traceMessages.Dequeue();
}
StringBuilder sb = new StringBuilder();
sb.Append(DateTime.Now.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff", CultureInfo.InvariantCulture));
sb.Append(" ");
@@ -53,7 +50,17 @@ namespace Newtonsoft.Json.Serialization
sb.Append(" ");
sb.Append(message);
_traceMessages.Enqueue(sb.ToString());
string s = sb.ToString();
lock (_lock)
{
if (_traceMessages.Count >= 1000)
{
_traceMessages.Dequeue();
}
_traceMessages.Enqueue(s);
}
}
/// <summary>
@@ -73,18 +80,21 @@ namespace Newtonsoft.Json.Serialization
/// </returns>
public override string ToString()
{
StringBuilder sb = new StringBuilder();
foreach (string traceMessage in _traceMessages)
lock (_lock)
{
if (sb.Length > 0)
StringBuilder sb = new StringBuilder();
foreach (string traceMessage in _traceMessages)
{
sb.AppendLine();
if (sb.Length > 0)
{
sb.AppendLine();
}
sb.Append(traceMessage);
}
sb.Append(traceMessage);
return sb.ToString();
}
return sb.ToString();
}
}
}