-
-
Notifications
You must be signed in to change notification settings - Fork 357
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
Calling Set() from AsyncManualResetEvent can potentially saturate the threadpool #48
Comments
That's some very interesting behavior! Internally, the I'll need to investigate this further and think about it a lot. On a side note, the new version of AMRE is using a newer underlying implementation based on .NET 4.6 / Core types, and it does not exhibit this behavior. Feel free to upgrade if you're on .NET 4.6. |
Thanks for the reply Stephen. The issue is indeed caused by the fact that AMRE.Set is blocking the thread until an action pushed on threadpool is executed. But unfortunately, as my sample shows, this can cause threadpool saturation if the Set method is called rapidly by all the threadppool threads. Based on Stephen Toub article, I am guessing that the goal of doing the logic that you do in the Set method is to avoid the synchronous continuation that would be executed as part of the Set method. From what I see in your new version of AMRE.Set(), you call directly the TrySetResult method on the TaskCompletionSource which will avoid the threadpool saturation issue but will have the side effect of executing the continuation synchronously as part of the Set method. Am I right by saying that or is there something different in .Net 4.6 that will not behave as in 4.5? |
Yes, that is one reason. Another is that my implementations are using regular locks, and one of the cardinal rules for locks is that you can't invoke arbitrary end-user callbacks (e.g., task continuations). The |
Thanks for the explanation. I will take a better look at your new implementation. As for the flag RunContinuationAsynchronously, I don't know if you were already aware of this bug, but there are some cases where the flag won't make the continuation run asynchronously in .Net 4.6 and 4.6.1. |
Note that the RunContinuationsAsynchronously flag had a bug in 4.6. It wasn't enforced if the task was passed to Task.WhenAll/WhenAny. The issue got fixed in 4.6.1 https://github.com/dotnet/coreclr/issues/2021 Edit I misread, the bug is still in .Net 4.6.1
|
Yeah, shame it's still in 4.6.1. I haven't seen any news anywhere for a 4.6.2. I guess //build might give us some new toys. |
Closing this due to a fix available in the new netstandard-based coordination library. |
Follow #71 for updates on the v5 (netstandard) release. |
The following sample will result in what appears to be threadpool saturation:
The output will show that the Set method is called rapidly for the first X available threads on the threadpool, and then start to slow down while the threadpool creates new threads.
On my machine, the default threadpool has 8 threads and it took 31 seconds before the last Set() could be called.
Does an async version of the Set method make sense? The following code solved my issue, but can this create any wrong side-effect that I don't see?
Thanks for the great library by the way!
The text was updated successfully, but these errors were encountered: