Merge branch 'thread-safe-store-perf' of https://github.com/TylerBrinkley/Newtonsoft.Json into TylerBrinkley-thread-safe-store-perf
This commit is contained in:
@@ -34,11 +34,11 @@
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition="'$(TargetFramework)'=='net45'">
|
||||
<AssemblyTitle>Json.NET</AssemblyTitle>
|
||||
<DefineConstants>HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_IMMUTABLE_COLLECTIONS;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_EMIT;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;$(AdditionalConstants)</DefineConstants>
|
||||
<DefineConstants>HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_IMMUTABLE_COLLECTIONS;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_EMIT;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;HAVE_CONCURRENT_DICTIONARY;$(AdditionalConstants)</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(TargetFramework)'=='net40'">
|
||||
<AssemblyTitle>Json.NET .NET 4.0</AssemblyTitle>
|
||||
<DefineConstants>NET40;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_REFLECTION_EMIT;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;$(AdditionalConstants)</DefineConstants>
|
||||
<DefineConstants>NET40;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_REFLECTION_EMIT;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;HAVE_CONCURRENT_DICTIONARY;$(AdditionalConstants)</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(TargetFramework)'=='net35'">
|
||||
<AssemblyTitle>Json.NET .NET 3.5</AssemblyTitle>
|
||||
@@ -63,7 +63,7 @@
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard1.3'">
|
||||
<AssemblyTitle>Json.NET .NET Standard 1.3</AssemblyTitle>
|
||||
<DefineConstants>NETSTANDARD1_3;PORTABLE;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_SERIALIZATION;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DYNAMIC;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_IMMUTABLE_COLLECTIONS;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_ISET;HAVE_LINQ;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_BINDER;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_OBSOLETE_FORMATTER_ASSEMBLY_STYLE;HAVE_XML_DOCUMENT;$(AdditionalConstants)</DefineConstants>
|
||||
<DefineConstants>NETSTANDARD1_3;PORTABLE;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_SERIALIZATION;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DYNAMIC;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_IMMUTABLE_COLLECTIONS;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_ISET;HAVE_LINQ;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_BINDER;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_OBSOLETE_FORMATTER_ASSEMBLY_STYLE;HAVE_XML_DOCUMENT;HAVE_CONCURRENT_DICTIONARY;$(AdditionalConstants)</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(TargetFramework)' == 'portable-net40+win8+wpa81+wp8+sl5'">
|
||||
<AssemblyTitle>Json.NET Portable .NET 4.0</AssemblyTitle>
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
#if HAVE_CONCURRENT_DICTIONARY
|
||||
using System.Collections.Concurrent;
|
||||
#endif
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
@@ -69,7 +72,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
private static readonly object TypeContractCacheLock = new object();
|
||||
private static readonly PropertyNameTable NameTable = new PropertyNameTable();
|
||||
private static Dictionary<ResolverContractKey, JsonContract> _contractCache;
|
||||
private static readonly ConcurrentDictionary<ResolverContractKey, JsonContract> _contractCache = new ConcurrentDictionary<ResolverContractKey, JsonContract>();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CamelCasePropertyNamesContractResolver"/> class.
|
||||
@@ -96,27 +99,8 @@ namespace Newtonsoft.Json.Serialization
|
||||
}
|
||||
|
||||
// for backwards compadibility the CamelCasePropertyNamesContractResolver shares contracts between instances
|
||||
JsonContract contract;
|
||||
ResolverContractKey key = new ResolverContractKey(GetType(), type);
|
||||
Dictionary<ResolverContractKey, JsonContract> cache = _contractCache;
|
||||
if (cache == null || !cache.TryGetValue(key, out contract))
|
||||
{
|
||||
contract = CreateContract(type);
|
||||
|
||||
// avoid the possibility of modifying the cache dictionary while another thread is accessing it
|
||||
lock (TypeContractCacheLock)
|
||||
{
|
||||
cache = _contractCache;
|
||||
Dictionary<ResolverContractKey, JsonContract> updatedCache = (cache != null)
|
||||
? new Dictionary<ResolverContractKey, JsonContract>(cache)
|
||||
: new Dictionary<ResolverContractKey, JsonContract>();
|
||||
updatedCache[key] = contract;
|
||||
|
||||
_contractCache = updatedCache;
|
||||
}
|
||||
}
|
||||
|
||||
return contract;
|
||||
return _contractCache.GetOrAdd(key, k => CreateContract(type));
|
||||
}
|
||||
|
||||
internal override PropertyNameTable GetNameTable()
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
#if HAVE_CONCURRENT_DICTIONARY
|
||||
using System.Collections.Concurrent;
|
||||
#endif
|
||||
using Newtonsoft.Json.Schema;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
@@ -47,6 +50,7 @@ using Newtonsoft.Json.Utilities.LinqBridge;
|
||||
using System.Linq;
|
||||
|
||||
#endif
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
@@ -92,7 +96,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
private readonly object _typeContractCacheLock = new object();
|
||||
private readonly PropertyNameTable _nameTable = new PropertyNameTable();
|
||||
|
||||
private Dictionary<Type, JsonContract> _contractCache;
|
||||
private readonly ConcurrentDictionary<Type, JsonContract> _contractCache = new ConcurrentDictionary<Type, JsonContract>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether members are being get and set using dynamic code generation.
|
||||
@@ -175,26 +179,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
throw new ArgumentNullException(nameof(type));
|
||||
}
|
||||
|
||||
JsonContract contract;
|
||||
Dictionary<Type, JsonContract> cache = _contractCache;
|
||||
if (cache == null || !cache.TryGetValue(type, out contract))
|
||||
{
|
||||
contract = CreateContract(type);
|
||||
|
||||
// avoid the possibility of modifying the cache dictionary while another thread is accessing it
|
||||
lock (_typeContractCacheLock)
|
||||
{
|
||||
cache = _contractCache;
|
||||
Dictionary<Type, JsonContract> updatedCache = (cache != null)
|
||||
? new Dictionary<Type, JsonContract>(cache)
|
||||
: new Dictionary<Type, JsonContract>();
|
||||
updatedCache[type] = contract;
|
||||
|
||||
_contractCache = updatedCache;
|
||||
}
|
||||
}
|
||||
|
||||
return contract;
|
||||
return _contractCache.GetOrAdd(type, CreateContract);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
#region License
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
#if !HAVE_CONCURRENT_DICTIONARY
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
internal sealed class ConcurrentDictionary<TKey, TValue>
|
||||
{
|
||||
private readonly object _lock = new object();
|
||||
private Dictionary<TKey, TValue> _dictionary = new Dictionary<TKey, TValue>();
|
||||
|
||||
public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
|
||||
{
|
||||
TValue value;
|
||||
if (!_dictionary.TryGetValue(key, out value))
|
||||
{
|
||||
return AddValue(key, valueFactory);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private TValue AddValue(TKey key, Func<TKey, TValue> valueFactory)
|
||||
{
|
||||
TValue value = valueFactory(key);
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
// double check locking
|
||||
TValue checkValue;
|
||||
if (_dictionary.TryGetValue(key, out checkValue))
|
||||
{
|
||||
return checkValue;
|
||||
}
|
||||
|
||||
Dictionary<TKey, TValue> newDictionary = new Dictionary<TKey, TValue>(_dictionary);
|
||||
newDictionary[key] = value;
|
||||
|
||||
#if HAVE_MEMORY_BARRIER
|
||||
Thread.MemoryBarrier();
|
||||
#endif
|
||||
_dictionary = newDictionary;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -24,19 +24,16 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
#if !HAVE_LINQ
|
||||
using Newtonsoft.Json.Utilities.LinqBridge;
|
||||
#if HAVE_CONCURRENT_DICTIONARY
|
||||
using System.Collections.Concurrent;
|
||||
#endif
|
||||
using System.Threading;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
internal class ThreadSafeStore<TKey, TValue>
|
||||
{
|
||||
private readonly object _lock = new object();
|
||||
private Dictionary<TKey, TValue> _store;
|
||||
private readonly ConcurrentDictionary<TKey, TValue> _store;
|
||||
private readonly Func<TKey, TValue> _creator;
|
||||
|
||||
public ThreadSafeStore(Func<TKey, TValue> creator)
|
||||
@@ -47,51 +44,12 @@ namespace Newtonsoft.Json.Utilities
|
||||
}
|
||||
|
||||
_creator = creator;
|
||||
_store = new Dictionary<TKey, TValue>();
|
||||
_store = new ConcurrentDictionary<TKey, TValue>();
|
||||
}
|
||||
|
||||
public TValue Get(TKey key)
|
||||
{
|
||||
TValue value;
|
||||
if (!_store.TryGetValue(key, out value))
|
||||
{
|
||||
return AddValue(key);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private TValue AddValue(TKey key)
|
||||
{
|
||||
TValue value = _creator(key);
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (_store == null)
|
||||
{
|
||||
_store = new Dictionary<TKey, TValue>();
|
||||
_store[key] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// double check locking
|
||||
TValue checkValue;
|
||||
if (_store.TryGetValue(key, out checkValue))
|
||||
{
|
||||
return checkValue;
|
||||
}
|
||||
|
||||
Dictionary<TKey, TValue> newStore = new Dictionary<TKey, TValue>(_store);
|
||||
newStore[key] = value;
|
||||
|
||||
#if HAVE_MEMORY_BARRIER
|
||||
Thread.MemoryBarrier();
|
||||
#endif
|
||||
_store = newStore;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
return _store.GetOrAdd(key, _creator);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user