Skip to content

Update code style #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
761 changes: 368 additions & 393 deletions AsyncLock/AsyncLock.cs

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions AsyncLock/AsyncLock.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard1.3;netstandard2.1</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<RootNamespace>NeoSmart.AsyncLock</RootNamespace>
<PackageId>NeoSmart.AsyncLock</PackageId>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
Expand Down Expand Up @@ -30,7 +31,6 @@
</PropertyGroup>

<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>AsyncLock.snk</AssemblyOriginatorKeyFile>
<PackageReadmeFile>README.md</PackageReadmeFile>
Expand Down
15 changes: 0 additions & 15 deletions AsyncLock/NullDisposable.cs

This file was deleted.

106 changes: 51 additions & 55 deletions UnitTests/AsyncIdTests.cs
Original file line number Diff line number Diff line change
@@ -1,82 +1,78 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NeoSmart.AsyncLock;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

#if false
namespace AsyncLockTests
namespace AsyncLockTests;

[TestClass]
public class AsyncIdTests
{
[TestClass]
public class AsyncIdTests
[TestMethod]
public void TaskIdUniqueness()
{
[TestMethod]
public void TaskIdUniqueness()
{
var testCount = 100;
var countdown = new CountdownEvent(testCount);
var failure = new ManualResetEventSlim(false);
var threadIds = new SortedSet<long>();
var abort = new SemaphoreSlim(0, 1);
var testCount = 100;
var countdown = new CountdownEvent(testCount);
var failure = new ManualResetEventSlim(false);
var threadIds = new SortedSet<long>();
var abort = new SemaphoreSlim(0, 1);

for (int i = 0; i < testCount; ++i)
for (int i = 0; i < testCount; ++i)
{
Task.Run(async () =>
{
Task.Run(async () =>
lock (threadIds)
{
lock (threadIds)
if (!threadIds.Add(AsyncLock.ThreadId))
{
if (!threadIds.Add(AsyncLock.ThreadId))
{
failure.Set();
}
failure.Set();
}
countdown.Signal();
await abort.WaitAsync();
});
}

if (WaitHandle.WaitAny(new[] { countdown.WaitHandle, failure.WaitHandle }) == 1)
{
Assert.Fail("A duplicate thread id was found!");
}

abort.Release();
}
countdown.Signal();
await abort.WaitAsync();
});
}

public void ThreadIdUniqueness()
if (WaitHandle.WaitAny([countdown.WaitHandle, failure.WaitHandle]) == 1)
{
var testCount = 100;
var countdown = new CountdownEvent(testCount);
var failure = new ManualResetEventSlim(false);
var threadIds = new SortedSet<long>();
var abort = new SemaphoreSlim(0, 1);
Assert.Fail("A duplicate thread id was found!");
}

abort.Release();
}

for (int i = 0; i < testCount; ++i)
public void ThreadIdUniqueness()
{
var testCount = 100;
var countdown = new CountdownEvent(testCount);
var failure = new ManualResetEventSlim(false);
var threadIds = new SortedSet<long>();
var abort = new SemaphoreSlim(0, 1);

for (int i = 0; i < testCount; ++i)
{
Task.Run(async () =>
{
Task.Run(async () =>
lock (threadIds)
{
lock (threadIds)
if (!threadIds.Add(AsyncLock.ThreadId))
{
if (!threadIds.Add(AsyncLock.ThreadId))
{
failure.Set();
}
failure.Set();
}
countdown.Signal();
await abort.WaitAsync();
});
}

if (WaitHandle.WaitAny(new[] { countdown.WaitHandle, failure.WaitHandle }) == 1)
{
Assert.Fail("A duplicate thread id was found!");
}
}
countdown.Signal();
await abort.WaitAsync();
});
}

abort.Release();
if (WaitHandle.WaitAny([countdown.WaitHandle, failure.WaitHandle]) == 1)
{
Assert.Fail("A duplicate thread id was found!");
}

abort.Release();
}
}
#endif
100 changes: 49 additions & 51 deletions UnitTests/AsyncSpawn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,77 +2,75 @@
using NeoSmart.AsyncLock;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncLockTests
namespace AsyncLockTests;

/// <summary>
/// Creates multiple independent tasks, each with its own lock, and runs them
/// all in parallel. There should be no contention for the lock between the
/// parallelly executed tasks, but each task then recursively obtains what
/// should be the same lock - which should again be contention-free - after
/// an await point that may or may not resume on the same actual thread the
/// previous lock was obtained with.
/// </summary>
[TestClass]
public class AsyncSpawn
{
/// <summary>
/// Creates multiple independent tasks, each with its own lock, and runs them
/// all in parallel. There should be no contention for the lock between the
/// parallelly executed tasks, but each task then recursively obtains what
/// should be the same lock - which should again be contention-free - after
/// an await point that may or may not resume on the same actual thread the
/// previous lock was obtained with.
/// </summary>
[TestClass]
public class AsyncSpawn
public readonly struct NullDisposable : IDisposable
{
public readonly struct NullDisposable : IDisposable
{
public void Dispose() { }
}
public void Dispose() { }
}

public async Task AsyncExecution(bool locked)
{
var count = 0;
var tasks = new List<Task>(70);
var asyncLock = new AsyncLock();
var rng = new Random();

public async Task AsyncExecution(bool locked)
{
var count = 0;
var tasks = new List<Task>(70);
var asyncLock = new AsyncLock();
var rng = new Random();
using var l = locked ? await asyncLock.LockAsync() : new NullDisposable();

for (int i = 0; i < 10; ++i)
{
using var l = locked ? await asyncLock.LockAsync() : new NullDisposable();

for (int i = 0; i < 10; ++i)
var task = Task.Run(async () =>
{
var task = Task.Run(async () =>
using (await asyncLock.LockAsync())
{
Assert.AreEqual(1, Interlocked.Increment(ref count));
await Task.Yield();
Assert.AreEqual(1, count);
await Task.Delay(rng.Next(1, 10) * 10);
using (await asyncLock.LockAsync())
{
Assert.AreEqual(Interlocked.Increment(ref count), 1);
await Task.Yield();
Assert.AreEqual(count, 1);
await Task.Delay(rng.Next(1, 10) * 10);
using (await asyncLock.LockAsync())
{
await Task.Delay(rng.Next(1, 10) * 10);
Assert.AreEqual(Interlocked.Decrement(ref count), 0);
}

Assert.AreEqual(count, 0);
Assert.AreEqual(0, Interlocked.Decrement(ref count));
}

});
tasks.Add(task);
}
Assert.AreEqual(0, count);
}

});
tasks.Add(task);
}
}

await Task.WhenAll(tasks);
await Task.WhenAll(tasks);

Assert.AreEqual(count, 0);
}
Assert.AreEqual(0, count);
}

[TestMethod]
public async Task AsyncExecutionLocked()
{
await AsyncExecution(true);
}
[TestMethod]
public async Task AsyncExecutionLocked()
{
await AsyncExecution(true);
}

[TestMethod]
public async Task AsyncExecutionUnlocked()
{
await AsyncExecution(false);
}
[TestMethod]
public async Task AsyncExecutionUnlocked()
{
await AsyncExecution(false);
}
}
Loading