-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Apply double check pattern to avoid race condition in LoggingService #11284
base: main
Are you sure you want to change the base?
Apply double check pattern to avoid race condition in LoggingService #11284
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think I understand how this helps. Isn't there still a race between thread 1 seeing that it's non-null and calling into it and thread 2 calling Dispose()
?
95adccd
to
3611f9a
Compare
50d0c8c
to
74a1a74
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot reviewed 1 out of 1 changed files in this pull request and generated no comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's discuss this one
_emptyQueueEvent.Set(); | ||
_emptyQueueEvent?.Set(); | ||
} | ||
catch (Exception) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's try to avoid this - we'd have no indications of unexpected behavior from labs or watsons
// Long-lived event handles that never get disposed to avoid race conditions. | ||
private readonly AutoResetEvent _longLivedDequeueEvent = new AutoResetEvent(false); | ||
private readonly ManualResetEvent _longLivedEmptyQueueEvent = new ManualResetEvent(true); | ||
private readonly AutoResetEvent _longLivedEnqueueEvent = new AutoResetEvent(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are those needed?
{ | ||
_emptyQueueEvent.Set(); | ||
// Check if instance fields are nulled (cleanup was called) | ||
if (_eventQueue == null || _dequeueEvent == null || _emptyQueueEvent == null || _enqueueEvent == null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These can still get nullified right after checking.
We should store them in local variables and check and use those here. Then nullyfying in the close method could be kept
Fixes: https://dev.azure.com/devdiv/DevDiv/_workitems/edit/2320135/
Context
Reset()
method invocation sometimes causes exceptionSystem.IO.IOException: 'The handle is invalid.'
.Very likely it happens on application shutdown.
The assumption is:
Changes Made
To resolve this issue, the double-check pattern was implemented for the event fields.
This double-check approach prevents the 'invalid handle' exception from occurring during the race condition between component shutdown and the execution of the logging thread.
Testing
N/A