Context
NUnit PR#5192 introduced a Thread.Sleep() call inside async test infrastructure code. Thread.Sleep blocks a thread pool thread for the full sleep duration without releasing it. In an async context, this defeats the purpose of async - instead of yielding the thread while waiting, the code holds it, contributing to thread pool starvation under parallel test execution. The same PR also introduced a new static mutable field without synchronization.
Diff evidence
[GCI0016] Concurrency and State Risk
Summary : Thread.Sleep() in async context detected - blocks thread pool thread.
Evidence : Thread.Sleep(100); in async method WaitForConditionAsync
Why : Thread.Sleep blocks the calling thread for the full duration. In async
contexts this defeats cooperative yielding and contributes to thread
pool starvation under parallel workloads.
Action : Replace Thread.Sleep with await Task.Delay() to yield the thread.Why it matters
The irony of a Thread.Sleep in the NUnit source itself is significant. NUnit is the test framework used to validate that code is correct. If the framework's own async infrastructure blocks threads, it can cause intermittent test timeouts under parallel execution (the default in modern .NET test runs), mask real timing bugs because the test environment does not match production async behavior, and create false passes or failures that developers learn to ignore. Every project using NUnit async tests inherits this behavior.
Detection rule
This finding is produced by GCI0016 - Concurrency and State Risk. The rule flags Thread.Sleep inside async methods, unsynchronized static mutable state, and other patterns that cause thread pool starvation or data races.
