Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
doug144 committed Feb 24, 2019
1 parent ca5b1d5 commit 8ee0906
Show file tree
Hide file tree
Showing 9 changed files with 234 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ bld/

# Visual Studio 2015/2017 cache/options directory
.vs/
# VS Code cache/options directory
.vscode/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

Expand Down
69 changes: 69 additions & 0 deletions KeyedLock.UnitTests/HashedKeyedLockTests.cs
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);
}
}
}
20 changes: 20 additions & 0 deletions KeyedLock.UnitTests/KeyedLock.UnitTests.csproj
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>
37 changes: 37 additions & 0 deletions KeyedLock.UnitTests/KeyedLockTests.cs
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);
}
}
}
25 changes: 25 additions & 0 deletions KeyedLock/HashedKeyedLock.cs
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;
}
}
}
10 changes: 10 additions & 0 deletions KeyedLock/IKeyedLock.cs
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);
}
}
12 changes: 12 additions & 0 deletions KeyedLock/KeyedLock.cs
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){}
}
}
11 changes: 11 additions & 0 deletions KeyedLock/KeyedLock.csproj
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>
48 changes: 48 additions & 0 deletions Locking.sln
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

0 comments on commit 8ee0906

Please sign in to comment.