diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2012-04-27 07:02:58 -0700 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2012-04-27 07:02:58 -0700 |
commit | a6aea8aeeb82e3d35c132e6d09c9cb572efd823d (patch) | |
tree | 98e2e74156ab1371ab608d1bdf85dfe4ca255c78 | |
parent | 3b36cc6f6729a6f3f8dc478ff464960920aff653 (diff) | |
download | DotNetOpenAuth-a6aea8aeeb82e3d35c132e6d09c9cb572efd823d.zip DotNetOpenAuth-a6aea8aeeb82e3d35c132e6d09c9cb572efd823d.tar.gz DotNetOpenAuth-a6aea8aeeb82e3d35c132e6d09c9cb572efd823d.tar.bz2 |
Fixes thread-safety in MessageDescriptionCollection class.
Fixes #130
-rw-r--r-- | src/DotNetOpenAuth.Core/Messaging/Reflection/MessageDescriptionCollection.cs | 22 |
1 files changed, 17 insertions, 5 deletions
diff --git a/src/DotNetOpenAuth.Core/Messaging/Reflection/MessageDescriptionCollection.cs b/src/DotNetOpenAuth.Core/Messaging/Reflection/MessageDescriptionCollection.cs index 1fa9252..3517abc 100644 --- a/src/DotNetOpenAuth.Core/Messaging/Reflection/MessageDescriptionCollection.cs +++ b/src/DotNetOpenAuth.Core/Messaging/Reflection/MessageDescriptionCollection.cs @@ -9,6 +9,7 @@ namespace DotNetOpenAuth.Messaging.Reflection { using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; + using System.Linq; /// <summary> /// A cache of <see cref="MessageDescription"/> instances. @@ -35,7 +36,10 @@ namespace DotNetOpenAuth.Messaging.Reflection { /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection. /// </returns> public IEnumerator<MessageDescription> GetEnumerator() { - return this.reflectedMessageTypes.Values.GetEnumerator(); + lock (this.reflectedMessageTypes) { + // We must clone the collection so that it's thread-safe to the caller as it leaves our lock. + return this.reflectedMessageTypes.Values.ToList().GetEnumerator(); + } } #endregion @@ -49,7 +53,7 @@ namespace DotNetOpenAuth.Messaging.Reflection { /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection. /// </returns> System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { - return this.reflectedMessageTypes.Values.GetEnumerator(); + return this.GetEnumerator(); } #endregion @@ -71,15 +75,23 @@ namespace DotNetOpenAuth.Messaging.Reflection { MessageTypeAndVersion key = new MessageTypeAndVersion(messageType, messageVersion); MessageDescription result; - if (!this.reflectedMessageTypes.TryGetValue(key, out result)) { + lock (this.reflectedMessageTypes) { + this.reflectedMessageTypes.TryGetValue(key, out result); + } + + if (result == null) { + // Construct the message outside the lock. + var newDescription = new MessageDescription(messageType, messageVersion); + + // Then use the lock again to either acquire what someone else has created in the meantime, or + // set and use our own result. lock (this.reflectedMessageTypes) { if (!this.reflectedMessageTypes.TryGetValue(key, out result)) { - this.reflectedMessageTypes[key] = result = new MessageDescription(messageType, messageVersion); + this.reflectedMessageTypes[key] = result = newDescription; } } } - Contract.Assume(result != null, "We should never assign null values to this dictionary."); return result; } |