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

Use ConcurrentDictionary to avoid threading issues #104407

Merged
merged 7 commits into from
Jul 8, 2024

Conversation

steveharter
Copy link
Member

@steveharter steveharter commented Jul 3, 2024

Address various threading issues including:
Fixes #104221
Fixes #103823
Fixes #102136

Local testing included running all tests in a loop 300x in both Release and Debug builds.

Linking here other threading issues fixed in this area fixed during 9.0:
#30024
#92394
#97179
#103265

@steveharter steveharter requested a review from buyaa-n July 5, 2024 16:02
@steveharter steveharter marked this pull request as ready for review July 5, 2024 16:02
Copy link
Contributor

@AustinWise AustinWise left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could potentially use features of the ConcurrentDictionary to avoid the need for a lock. See this gist: https://gist.github.com/AustinWise/92f293463124cdbf95e702946502b636

_valueChangedHandlers[component] = h;
}
else
lock (SyncObject)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
lock (SyncObject)
while (true)
{
EventHandler? existingHandler;
if (!_valueChangedHandlers.TryGetValue(component, out existingHandler))
{
break;
}
EventHandler? replacementHandler = (EventHandler?)Delegate.Remove(existingHandler, handler);
if (replacementHandler is null)
{
if (_valueChangedHandlers.TryRemove(new KeyValuePair<object, EventHandler?>(component, existingHandler)))
{
break;
}
}
else
{
if (_valueChangedHandlers.TryUpdate(component, replacementHandler, existingHandler))
{
break;
}
}
}

I intend for this to replace the entire lock block, but GitHub won't let me make that suggestion. See here for what it should look like: https://gist.github.com/AustinWise/92f293463124cdbf95e702946502b636#file-propertydescriptor-cs-L62

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think using the lock as-is is more straightforward. Also, the Remove is not likely to be used as often.

Copy link
Contributor

@buyaa-n buyaa-n left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@steveharter steveharter merged commit 670d11f into dotnet:main Jul 8, 2024
81 of 83 checks passed
@steveharter steveharter deleted the ReflectionProviderThread branch July 8, 2024 16:43
@github-actions github-actions bot locked and limited conversation to collaborators Aug 9, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
6 participants