ProcessThreadTests.TestStartTimeProperty - Get spawned thread by ID from Process.Threads to avoid mismatch#104972
Conversation
…Tests.TestStartTimeProperty test, fixes dotnet#103448
|
Tagging subscribers to this area: @dotnet/area-system-diagnostics-process |
|
Although, I think @jozkee has a point in his comment in the issue, that tolerating such wrong timestamps is probably masking a real bug rather than just accommodating test noise. |
…atch block: - it can hide LINQ issues as LINQ may throw InvalidOperationException - it's not needed for the current thread, because the code is still running so we know the thread is alive
…ssThreadTests.TestStartTimeProperty test, fixes dotnet#103448" This reverts commit 3092d86.
|
Hmm, is the likely reason for the failure that |
src/libraries/System.Diagnostics.Process/tests/ProcessThreadTests.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Diagnostics.Process/tests/ProcessThreadTests.cs
Outdated
Show resolved
Hide resolved
| p.Refresh(); | ||
| try | ||
| { | ||
| var newest = p.Threads.Cast<ProcessThread>().OrderBy(t => t.StartTime.ToUniversalTime()).Last(); |
There was a problem hiding this comment.
Was it wrongly assumed that Process.Threads contained the threads ordered with the most recently created as the Last() one?
Is also possible that the property does have the threads ordered but StartNew wasn't creating a new thread but reusing an existing one as Dan mentioned.
There was a problem hiding this comment.
Was it wrongly assumed that Process.Threads contained the threads ordered with the most recently created as the Last() one?
There are other tests running in parallel and each of them can create a new thread. Even if we disable that, the ThreadPool can still start a new thread on it's own. So to get 100% deterministic behavior we should IMO perform an ID match.
There was a problem hiding this comment.
StartNew wasn't creating a new thread but reusing an existing one as Dan mentioned.
In theory CLR and Mono are sharing the same thread pool implementation, so I would expect TaskCreationOptions.LongRunning to always create a new thread, but I might be wrong.
@kouvel is it safe to assume that Task.Factory.StartNew(/**/, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); executed from an xUnit test runner will always spawn a new thread?
There was a problem hiding this comment.
Based on this:
It looks like when thread start is supported, a new thread is created for each long-running task. The threads used for long-running tasks are not pooled currently, though they could be. Probably creating a new thread would be more explicit in intent.
Wonder if the failure is happening when thread start is not supported. In the threading tests that create new threads, the following condition is used, which appears to be the same condition as Thread.IsThreadStartSupported:
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
There was a problem hiding this comment.
Although using a long-running task would avoid an unhandled exception/crash on assertion failure in the new thread. ThreadTestHelpers.CreateGuardedThread could be used for that instead, as in:
There was a problem hiding this comment.
The threads used for long-running tasks are not pooled currently, though they could be.
TIL - I should have checked the code. @kouvel is that worth an issue, as a suggestion? Basically pull a thread from the pool if available, and trigger a replacement to start. I have no idea.
There was a problem hiding this comment.
What's done currently is simple and may be sufficient if most long-running work items rarely or never complete. If there's a need where work items would complete frequently enough, and are not short enough and need to be classified as long-running, then it may be worthwhile to pool those threads.
jozkee
left a comment
There was a problem hiding this comment.
LGTM, assuming CI passes, thanks!
| ProcessThread[] processThreads = p.Threads.Cast<ProcessThread>().ToArray(); | ||
| ProcessThread newThread = Assert.Single(processThreads, thread => thread.Id == newThreadId); | ||
|
|
||
| Assert.InRange(newThread.StartTime.ToUniversalTime(), curTime - allowedWindow, DateTime.Now.ToUniversalTime() + allowedWindow); |
There was a problem hiding this comment.
Now that we get the correct thread, could we get rid of the tolerance?
There was a problem hiding this comment.
I've reverted the increase of the tolerance. I think it's safer to keep the current one (I am just afraid it would make the test even more flaky)
There was a problem hiding this comment.
I think with your fix the test won't be flaky at all 😆 but I might be wrong.
…x the build for arm64)
fixes #103448