Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NRE on Dispose in ExecutionTimer #779

Closed
dee-see opened this issue Oct 22, 2018 · 4 comments
Closed

NRE on Dispose in ExecutionTimer #779

dee-see opened this issue Oct 22, 2018 · 4 comments
Labels

Comments

@dee-see
Copy link
Contributor

dee-see commented Oct 22, 2018

I'm breakpointing through the PSES to figure out how the Find References mechanism works for another issue and I'm getting NRE in ExecutionTimer quite frequently.

The NRE happens on the first line of the Dispose() method.

t_stopwatch.Stop();

It's happening here and in other similar blocks of code

using (Logger.LogExecutionTime($"Script analysis of {scriptFile.FilePath} completed."))
{
    semanticMarkers = await editorSession.AnalysisService.GetSemanticMarkersAsync(scriptFile);
}

Basically the ThreadStatic t_stopwatch field is assigned inside the Logger.LogExecutionTime call, but when we come back from the 'await' the code is/can be executed on another thread and Logger.LogExecutionTime is either null, the right t_stopwatch or one from another thread.

So before I submit a PR making t_stopwatch an instance field I wanted to ask why is it ThreadStatic? Am I going to break everything in a way I'm not seeing right now?

Thanks

(I'm running the application on Arch Linux, building with VS Code)

@rkeithhill
Copy link
Contributor

Hmm, unless someone messes with the SynchronizationContext, the continuation "should" happen on the thread that started the await.

@dee-see
Copy link
Contributor Author

dee-see commented Oct 22, 2018

Hmm ok I see. I'll try to write a unit test that reproduces the issue and figure out more precisely what's going on. Maybe it's a platform issue, I'll see if it behaves the same way on Windows.

EDIT: For what it's worth I'm getting different threads before and after the await in this fiddle https://dotnetfiddle.net/VSDAzA

@rjmholt
Copy link
Contributor

rjmholt commented Oct 22, 2018

The intent of the [ThreadStatic] attribute was to prevent needing to do any thread handling on the stopwatch object. Since a stopwatch is expensive to create, I figured we'd have a static one. But to prevent thread contention that wouldn't exist otherwise, I made it threadstatic. I was hoping that we could keep the overhead of adding a stopwatch to a minimum.

However it sounds like I haven't accounted for managing async continuations moving to new threads properly. Given the choice between locking and creating a fresh stopwatch every time, I'd prefer to create the stopwatch. But otherwise, perhaps a "stopwatch pool" is in order?

@dee-see
Copy link
Contributor Author

dee-see commented Oct 22, 2018

Yeah unless we're timing a lot of things at the same time the pool might end up creating fewer stopwatches than the ThreadStatic implementation did.

Thanks for the information, I'll work on something to deal with the issue.

rjmholt pushed a commit that referenced this issue Oct 24, 2018
* Fix ThreadStatic issue with an object pool
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants