Merge branch '8-bug-indexoutofrangeexception-when-using-multi-threaded-consumers' into 'main'

Resolve "Bug: IndexOutOfRangeException when using multi-threaded consumers"

Closes #8

See merge request open-source/dotnet/FastRng!6
This commit is contained in:
Thorsten 2023-11-14 14:43:58 +00:00
commit d8f024a5c5
3 changed files with 36 additions and 4 deletions

View File

@ -3,9 +3,9 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net7.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<AssemblyVersion>1.1.1</AssemblyVersion> <AssemblyVersion>1.1.2</AssemblyVersion>
<FileVersion>1.1.1</FileVersion> <FileVersion>1.1.2</FileVersion>
<PackageVersion>1.1.1</PackageVersion> <PackageVersion>1.1.2</PackageVersion>
<Authors>Thorsten Sommer</Authors> <Authors>Thorsten Sommer</Authors>
<PackageProjectUrl>https://devops.tsommer.org/open-source/dotnet/FastRng</PackageProjectUrl> <PackageProjectUrl>https://devops.tsommer.org/open-source/dotnet/FastRng</PackageProjectUrl>
<RepositoryUrl>https://devops.tsommer.org/open-source/dotnet/FastRng</RepositoryUrl> <RepositoryUrl>https://devops.tsommer.org/open-source/dotnet/FastRng</RepositoryUrl>

View File

@ -295,6 +295,11 @@ public sealed class MultiThreadedRng<TNum> : IRandom<TNum>, IDisposable where TN
// Made a local copy of the current pointer: // Made a local copy of the current pointer:
var myPointer = this.currentBufferPointer; var myPointer = this.currentBufferPointer;
// Issue #8: This might happens when the current thread was interrupted by another thread, and
// the other thread has already updated the pointer. In this case, we start over again.
if (myPointer >= BUFFER_SIZE)
goto Start;
// Increment the pointer for the next thread or call: // Increment the pointer for the next thread or call:
var nextPointer = myPointer + 1; var nextPointer = myPointer + 1;
@ -303,7 +308,7 @@ public sealed class MultiThreadedRng<TNum> : IRandom<TNum>, IDisposable where TN
goto Start; goto Start;
// //
// Case: Success. We updated the pointer and, thus, can use the read number. // Case: Success. We updated the pointer and, thus, can use it to read the number.
// //
return this.currentBuffer[myPointer]; return this.currentBuffer[myPointer];
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using FastRng; using FastRng;
using FastRng.Distributions; using FastRng.Distributions;
using NUnit.Framework; using NUnit.Framework;
@ -223,6 +224,32 @@ public class MultiThreadedRngTests
Assert.That(lorentzContains1, Is.True, "Lorentz distribution does not contained 1"); Assert.That(lorentzContains1, Is.True, "Lorentz distribution does not contained 1");
} }
[Test]
[Category(TestCategories.LONG_RUNNING)]
public void TestMultiThreadedConsumer()
{
var job1 = Task.Factory.StartNew(Run, TaskCreationOptions.LongRunning);
var job2 = Task.Factory.StartNew(Run, TaskCreationOptions.LongRunning);
var job3 = Task.Factory.StartNew(Run, TaskCreationOptions.LongRunning);
Assert.DoesNotThrowAsync(async () => await job1);
Assert.DoesNotThrowAsync(async () => await job2);
Assert.DoesNotThrowAsync(async () => await job3);
return;
float Run()
{
var sum = 0f;
var distLorentz = new CauchyLorentzX1<float>(this.rng);
for (int i = 0; i < 100_000_000; i++)
{
sum += distLorentz.NextNumber();
}
return sum;
}
}
[Test] [Test]
[Category(TestCategories.COVER)] [Category(TestCategories.COVER)]
[Category(TestCategories.NORMAL)] [Category(TestCategories.NORMAL)]