Skip to content

Commit 2c62b06

Browse files
committed
Adding test to verify multi threaded random support, and adjusting implementation to use ThreadStatic for NET3X, ThreadLocal for anything else. Fixes bug with getting null Random instance when accessing on the second created thread, due to ThreadLocal variable only being instantiated once in the static constructor instead of once per thread.
1 parent 5432cd7 commit 2c62b06

File tree

2 files changed

+83
-9
lines changed

2 files changed

+83
-9
lines changed

ObjectFiller.Test/RandomAccessTest.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
namespace ObjectFiller.Test
2+
{
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Threading.Tasks;
7+
8+
using Xunit;
9+
10+
using ObjectFiller.Test.TestPoco.Library;
11+
using ObjectFiller.Test.TestPoco.Person;
12+
13+
using Tynamix.ObjectFiller;
14+
15+
16+
public class RandomAccessTest
17+
{
18+
[Fact]
19+
public void GetRandomIntOnDifferentThreadsGetsDifferentResults()
20+
{
21+
var numberToGenerate = 1000;
22+
var intRange = new IntRange(1, 10);
23+
var task1 = Task.Factory.StartNew(() =>
24+
{
25+
var taskResults = new List<int>();
26+
for (int i = 0; i < numberToGenerate; ++i)
27+
{
28+
taskResults.Add(Randomizer<int>.Create(intRange));
29+
}
30+
return taskResults;
31+
},
32+
TaskCreationOptions.LongRunning
33+
);
34+
var task2 = Task.Factory.StartNew(() =>
35+
{
36+
var taskResults = new List<int>();
37+
for (int i = 0; i < numberToGenerate; ++i)
38+
{
39+
taskResults.Add(Randomizer<int>.Create(intRange));
40+
}
41+
return taskResults;
42+
},
43+
TaskCreationOptions.LongRunning
44+
);
45+
var results = Task.WhenAll(task1, task2).Result;
46+
List<int> firstResults = results[0];
47+
List<int> secondResults = results[1];
48+
Assert.NotEqual(firstResults, secondResults);
49+
}
50+
}
51+
}

ObjectFiller/Random.cs

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,47 @@ namespace Tynamix.ObjectFiller
1919
/// </summary>
2020
internal static class Random
2121
{
22+
23+
private static int RandomSeed;
2224
/// <summary>
25+
/// Initializes static members of the <see cref="Random"/> class.
2326
/// A instance of <see cref="Random"/>
2427
/// </summary>
25-
[ThreadStatic]
26-
private static readonly System.Random Rnd;
28+
static Random()
29+
{
30+
RandomSeed = Environment.TickCount;
31+
}
2732

33+
#if NET3X
2834
/// <summary>
29-
/// Initializes static members of the <see cref="Random"/> class.
35+
/// A instance of <see cref="Random"/>
3036
/// </summary>
31-
static Random()
37+
[ThreadStatic]
38+
private static System.Random RndStorage;
39+
40+
private static System.Random Rnd
3241
{
33-
#if NETSTD
34-
Rnd = new System.Random();
42+
get
43+
{
44+
if (RndStorage == null)
45+
{
46+
RndStorage = new System.Random(Interlocked.Increment(ref RandomSeed));
47+
}
48+
return RndStorage;
49+
}
50+
}
3551
#else
36-
int seed = Environment.TickCount;
37-
Rnd = new System.Random(Interlocked.Increment(ref seed));
38-
#endif
52+
private static readonly ThreadLocal<System.Random> RndStorage = new ThreadLocal<System.Random>(() =>
53+
new System.Random(Interlocked.Increment(ref RandomSeed)));
54+
55+
/// <summary>
56+
/// A instance of <see cref="Random"/>
57+
/// </summary>
58+
private static System.Random Rnd
59+
{
60+
get { return RndStorage.Value; }
3961
}
62+
#endif
4063

4164
/// <summary>
4265
/// Returns a nonnegative number

0 commit comments

Comments
 (0)