diff options
author | Marius Ungureanu <marius.ungureanu@xamarin.com> | 2019-07-22 17:42:15 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-07-22 17:42:15 +0300 |
commit | 89aa4d323edcfac5ccdeeb1d221f9fc7b19ded0f (patch) | |
tree | 36f7f43d61278d7a3c75e6cc002deea5db40f1ce | |
parent | f3d2df0d337dbd080f37606a2900d496ab608e7d (diff) | |
parent | aff0f8d3dc2188a468f397cc9e49c7aed4f03bb6 (diff) |
Merge pull request #8253 from mono/service-locking
[Core] Add some extensions to ReaderWriterLockSlim and showcase usage
3 files changed, 99 insertions, 4 deletions
diff --git a/main/src/core/MonoDevelop.Core/CoreExtensions.ReaderWriterLockSlim.cs b/main/src/core/MonoDevelop.Core/CoreExtensions.ReaderWriterLockSlim.cs new file mode 100644 index 0000000000..b4805ff230 --- /dev/null +++ b/main/src/core/MonoDevelop.Core/CoreExtensions.ReaderWriterLockSlim.cs @@ -0,0 +1,90 @@ +// +// CoreExtensions.ReaderWriterLockSlim.cs +// +// Author: +// Marius Ungureanu <maungu@microsoft.com> +// +// Copyright (c) 2019 Microsoft Inc. +// +// 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. +using System; +using System.Threading; + +namespace System +{ + public static partial class CoreExtensions + { + internal static ReadLockExiter Read (this ReaderWriterLockSlim @lock) + => new ReadLockExiter (@lock); + + internal readonly struct ReadLockExiter : IDisposable + { + readonly ReaderWriterLockSlim _lock; + + internal ReadLockExiter (ReaderWriterLockSlim @lock) + { + _lock = @lock; + @lock.EnterReadLock (); + } + + public void Dispose () => _lock.ExitReadLock (); + } + + internal static UpgradeableReadLockExiter UpgradeableRead (this ReaderWriterLockSlim @lock) + => new UpgradeableReadLockExiter (@lock); + + internal readonly struct UpgradeableReadLockExiter : IDisposable + { + readonly ReaderWriterLockSlim _lock; + + internal UpgradeableReadLockExiter (ReaderWriterLockSlim @lock) + { + _lock = @lock; + @lock.EnterUpgradeableReadLock (); + } + + public void Dispose () + { + if (_lock.IsWriteLockHeld) { + _lock.ExitWriteLock (); + } + + _lock.ExitUpgradeableReadLock (); + } + + public void EnterWrite () => _lock.EnterWriteLock (); + } + + internal static WriteLockExiter Write (this ReaderWriterLockSlim @lock) + => new WriteLockExiter (@lock); + + internal readonly struct WriteLockExiter : IDisposable + { + readonly ReaderWriterLockSlim _lock; + + internal WriteLockExiter (ReaderWriterLockSlim @lock) + { + _lock = @lock; + @lock.EnterWriteLock (); + } + + public void Dispose () => _lock.ExitWriteLock (); + } + } +} diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs index 8817782fed..5eb2a9b08d 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs @@ -234,22 +234,26 @@ namespace MonoDevelop.Core.Assemblies return aname; } + static readonly ReaderWriterLockSlim readerWriterLock = new ReaderWriterLockSlim (); static readonly Dictionary<string, AssemblyName> assemblyNameCache = new Dictionary<string, AssemblyName> (); internal static AssemblyName GetAssemblyNameObj (string file) { AssemblyName name; - lock (assemblyNameCache) { + using (readerWriterLock.Read ()) { if (assemblyNameCache.TryGetValue (file, out name)) return name; } try { name = AssemblyName.GetAssemblyName (file); - lock (assemblyNameCache) { - assemblyNameCache [file] = name; + + using (readerWriterLock.Write ()) { + if (assemblyNameCache.TryGetValue (file, out var alreadyAdded)) + return alreadyAdded; + + return assemblyNameCache [file] = name; } - return name; } catch (FileNotFoundException) { // GetAssemblyName is not case insensitive in mono/windows. This is a workaround foreach (string f in Directory.GetFiles (Path.GetDirectoryName (file), Path.GetFileName (file))) { diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj index e1ec35552d..63d61dadf9 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj @@ -741,6 +741,7 @@ <Compile Include="CoreExtensions.Memoize.cs" /> <Compile Include="CoreExtensions.EventHandlers.cs" /> <Compile Include="CoreExtensions.Array.cs" /> + <Compile Include="CoreExtensions.ReaderWriterLockSlim.cs" /> </ItemGroup> <ItemGroup> <None Include="BuildVariables.cs.in" /> |