diff --git a/src/System.Threading.Timer/tests/System.Threading.Timer.Tests.csproj b/src/System.Threading.Timer/tests/System.Threading.Timer.Tests.csproj index 2bb3c8ebefd5..d4b83860cfa4 100644 --- a/src/System.Threading.Timer/tests/System.Threading.Timer.Tests.csproj +++ b/src/System.Threading.Timer/tests/System.Threading.Timer.Tests.csproj @@ -3,6 +3,7 @@ {ac20a28f-fda8-45e8-8728-058ead16e44c} netcoreapp-Debug;netcoreapp-Release;netstandard-Debug;netstandard-Release true + true @@ -12,4 +13,9 @@ + + + CommonTest\System\Threading\ThreadTestHelpers.cs + + \ No newline at end of file diff --git a/src/System.Threading.Timer/tests/TimerFiringTests.cs b/src/System.Threading.Timer/tests/TimerFiringTests.cs index 00006f68f0df..375df334653b 100644 --- a/src/System.Threading.Timer/tests/TimerFiringTests.cs +++ b/src/System.Threading.Timer/tests/TimerFiringTests.cs @@ -10,6 +10,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using System.Threading.Tests; using Xunit; using Xunit.Sdk; @@ -337,4 +338,57 @@ private static async Task PeriodAsync(int period, int iterations) await tcs.Task.ConfigureAwait(false); } } + + [Fact] + public void TimersCreatedConcurrentlyOnDifferentThreadsAllFire() + { + int processorCount = Environment.ProcessorCount; + + int timerTickCount = 0; + TimerCallback timerCallback = _ => Interlocked.Increment(ref timerTickCount); + + var threadStarted = new AutoResetEvent(false); + var createTimers = new ManualResetEvent(false); + var timers = new Timer[processorCount]; + Action createTimerThreadStart = data => + { + int i = (int)data; + var sw = new Stopwatch(); + threadStarted.Set(); + createTimers.WaitOne(); + + // Use the CPU a bit around creating the timer to try to have some of these threads run concurrently + sw.Restart(); + do + { + Thread.SpinWait(1000); + } while (sw.ElapsedMilliseconds < 10); + + timers[i] = new Timer(timerCallback, null, 1, Timeout.Infinite); + + // Use the CPU a bit around creating the timer to try to have some of these threads run concurrently + sw.Restart(); + do + { + Thread.SpinWait(1000); + } while (sw.ElapsedMilliseconds < 10); + }; + + var waitsForThread = new Action[timers.Length]; + for (int i = 0; i < timers.Length; ++i) + { + var t = ThreadTestHelpers.CreateGuardedThread(out waitsForThread[i], createTimerThreadStart); + t.IsBackground = true; + t.Start(i); + threadStarted.CheckedWait(); + } + + createTimers.Set(); + ThreadTestHelpers.WaitForCondition(() => timerTickCount == timers.Length); + + foreach (var waitForThread in waitsForThread) + { + waitForThread(); + } + } }