-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
234 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
using FluentAssertions; | ||
using System.Collections.Generic; | ||
|
||
namespace KeyedLock.UnitTests | ||
{ | ||
[TestClass] | ||
public class HashedKeyedLockTests | ||
{ | ||
private Dictionary<string, int> _dict; | ||
private HashedKeyedLock<string, int> _locker; | ||
|
||
[TestInitialize] | ||
public void TestInitialize() | ||
{ | ||
_dict = new Dictionary<string, int>(); | ||
_locker = new HashedKeyedLock<string, int>(x => _dict.GetValueOrDefault(x)); | ||
} | ||
|
||
[TestMethod] | ||
public void GetLockByString_SameKey_SameLock() | ||
{ | ||
//arrange | ||
const string key = "test"; | ||
_dict[key] = 1; | ||
|
||
//act | ||
var sem = _locker[key]; | ||
var sem2 = _locker[key]; | ||
|
||
//assert | ||
sem.Should().Be(sem2); | ||
} | ||
|
||
[TestMethod] | ||
public void GetLockByString_DifferentKey_DifferentLock() | ||
{ | ||
//arrange | ||
const string key = "test"; | ||
const string key2 = "other test"; | ||
_dict[key] = 1; | ||
_dict[key2] = 2; | ||
|
||
//act | ||
var sem = _locker[key]; | ||
var sem2 = _locker[key2]; | ||
|
||
//assert | ||
sem.Should().NotBe(sem2); | ||
} | ||
|
||
[TestMethod] | ||
public void GetLockByString_DifferentKeySameHash_DifferentLock() | ||
{ | ||
//arrange | ||
const string key = "test"; | ||
const string key2 = "other test"; | ||
_dict[key] = 1; | ||
_dict[key2] = 1; | ||
|
||
//act | ||
var sem = _locker[key]; | ||
var sem2 = _locker[key2]; | ||
|
||
//assert | ||
sem.Should().Be(sem2); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>netcoreapp2.2</TargetFramework> | ||
|
||
<IsPackable>false</IsPackable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="fluentassertions" Version="5.6.0" /> | ||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" /> | ||
<PackageReference Include="MSTest.TestAdapter" Version="1.3.2" /> | ||
<PackageReference Include="MSTest.TestFramework" Version="1.3.2" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\KeyedLock\KeyedLock.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
using FluentAssertions; | ||
|
||
namespace KeyedLock.UnitTests | ||
{ | ||
[TestClass] | ||
public class KeyedLockTests | ||
{ | ||
[TestMethod] | ||
public void GetLockByString_SameKey_SameLock() | ||
{ | ||
//arrange | ||
var locker = new KeyedLock<string>(); | ||
|
||
//act | ||
var sem = locker["test"]; | ||
var sem2 = locker["test"]; | ||
|
||
//assert | ||
sem.Should().Be(sem2); | ||
} | ||
|
||
[TestMethod] | ||
public void GetLockByString_DifferentKey_DifferentLock() | ||
{ | ||
//arrange | ||
var locker = new KeyedLock<string>(); | ||
|
||
//act | ||
var sem = locker["test"]; | ||
var sem2 = locker["other test"]; | ||
|
||
//assert | ||
sem.Should().NotBe(sem2); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using System; | ||
using System.Collections.Concurrent; | ||
using System.Threading; | ||
|
||
namespace KeyedLock | ||
{ | ||
public class HashedKeyedLock<TKey, THashedKey> | ||
{ | ||
private readonly ConcurrentDictionary<THashedKey, SemaphoreSlim> _dictionary = new ConcurrentDictionary<THashedKey, SemaphoreSlim>(); | ||
private readonly Func<TKey, THashedKey> _hash; | ||
private readonly int _maxReaders; | ||
|
||
public SemaphoreSlim this[TKey key] => _dictionary.GetOrAdd(_hash(key), _ => new SemaphoreSlim(1,_maxReaders)); | ||
|
||
public HashedKeyedLock(Func<TKey, THashedKey> hash) : this (hash, 1) | ||
{ | ||
} | ||
|
||
public HashedKeyedLock(Func<TKey, THashedKey> hash, int maxReaders) | ||
{ | ||
_hash = hash; | ||
_maxReaders = maxReaders; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
using System.Threading.Tasks; | ||
|
||
namespace KeyedLock | ||
{ | ||
public interface IKeyedLock<T> | ||
{ | ||
Task WaitAsync(T key); | ||
void Wait(T key); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using System.Collections.Concurrent; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace KeyedLock | ||
{ | ||
public class KeyedLock<TKey> : HashedKeyedLock<TKey, TKey> | ||
{ | ||
public KeyedLock() : this(1){} | ||
public KeyedLock(int maxReaders) : base(x => x, maxReaders){} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>netstandard2.0</TargetFramework> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="system.threading" Version="4.3.0" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio 15 | ||
VisualStudioVersion = 15.0.26124.0 | ||
MinimumVisualStudioVersion = 15.0.26124.0 | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeyedLock", "KeyedLock\KeyedLock.csproj", "{4A807DCD-16A7-4BA2-B6FD-1C3A4A83B980}" | ||
EndProject | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeyedLock.UnitTests", "KeyedLock.UnitTests\KeyedLock.UnitTests.csproj", "{223D0118-BDEC-4E83-B6D6-98325C3CE2BD}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Debug|x64 = Debug|x64 | ||
Debug|x86 = Debug|x86 | ||
Release|Any CPU = Release|Any CPU | ||
Release|x64 = Release|x64 | ||
Release|x86 = Release|x86 | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{4A807DCD-16A7-4BA2-B6FD-1C3A4A83B980}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{4A807DCD-16A7-4BA2-B6FD-1C3A4A83B980}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{4A807DCD-16A7-4BA2-B6FD-1C3A4A83B980}.Debug|x64.ActiveCfg = Debug|Any CPU | ||
{4A807DCD-16A7-4BA2-B6FD-1C3A4A83B980}.Debug|x64.Build.0 = Debug|Any CPU | ||
{4A807DCD-16A7-4BA2-B6FD-1C3A4A83B980}.Debug|x86.ActiveCfg = Debug|Any CPU | ||
{4A807DCD-16A7-4BA2-B6FD-1C3A4A83B980}.Debug|x86.Build.0 = Debug|Any CPU | ||
{4A807DCD-16A7-4BA2-B6FD-1C3A4A83B980}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{4A807DCD-16A7-4BA2-B6FD-1C3A4A83B980}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{4A807DCD-16A7-4BA2-B6FD-1C3A4A83B980}.Release|x64.ActiveCfg = Release|Any CPU | ||
{4A807DCD-16A7-4BA2-B6FD-1C3A4A83B980}.Release|x64.Build.0 = Release|Any CPU | ||
{4A807DCD-16A7-4BA2-B6FD-1C3A4A83B980}.Release|x86.ActiveCfg = Release|Any CPU | ||
{4A807DCD-16A7-4BA2-B6FD-1C3A4A83B980}.Release|x86.Build.0 = Release|Any CPU | ||
{223D0118-BDEC-4E83-B6D6-98325C3CE2BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{223D0118-BDEC-4E83-B6D6-98325C3CE2BD}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{223D0118-BDEC-4E83-B6D6-98325C3CE2BD}.Debug|x64.ActiveCfg = Debug|Any CPU | ||
{223D0118-BDEC-4E83-B6D6-98325C3CE2BD}.Debug|x64.Build.0 = Debug|Any CPU | ||
{223D0118-BDEC-4E83-B6D6-98325C3CE2BD}.Debug|x86.ActiveCfg = Debug|Any CPU | ||
{223D0118-BDEC-4E83-B6D6-98325C3CE2BD}.Debug|x86.Build.0 = Debug|Any CPU | ||
{223D0118-BDEC-4E83-B6D6-98325C3CE2BD}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{223D0118-BDEC-4E83-B6D6-98325C3CE2BD}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{223D0118-BDEC-4E83-B6D6-98325C3CE2BD}.Release|x64.ActiveCfg = Release|Any CPU | ||
{223D0118-BDEC-4E83-B6D6-98325C3CE2BD}.Release|x64.Build.0 = Release|Any CPU | ||
{223D0118-BDEC-4E83-B6D6-98325C3CE2BD}.Release|x86.ActiveCfg = Release|Any CPU | ||
{223D0118-BDEC-4E83-B6D6-98325C3CE2BD}.Release|x86.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
EndGlobal |