mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2026-01-06 17:10:13 +00:00
Now this is a nice bug that was found accidentally by ArchiBoT...
ReaderWriterLockSlim() is very decent solution, but it's thread-based, and we're using our ConcurrentHashSet in mixed async/sync context. This means that if we use something like:
foreach (var item in concHashSet) {
await AnythingAsync().ConfigureAwait(false);
}
It's totally possible that we'll request read lock as thread 1, and release the read lock as thread 2, which will lead to RWLock exception => System.Threading.SynchronizationLockException: The read lock is being released without being held.
Fortunately it looks like we didn't have any scenario like this in ASF, as this was possible only when we async/await while enumerating over ConcurrentHashSet, so that specific bug didn't affect ASF codebase (yet). Still, I must fix this as current implementation is not thread-safe, so our HashSet is in fact not concurrent in the first place.
I analyzed possible solutions and there are basically 3: either using ConcurrentDictionary and wrapping around it, replacing lock with SemaphoreSlim, or using third-party AsyncReaderWriterLock from StephenCleary. SemaphoreSlim entirely kills the concept of multiple readers one writer, and could affect performance negatively, moreover - it doesn't support upgreadable lock scenario we have with ReplaceIfNeededWith(). Concurrent dictionary would be nice if I didn't have that awful memory hit from storing mandatory pointless value, plus I don't really like concept of wrapping around conc dictionary if I can simply use it right away and drop my conc hashset entirely. AsyncReaderWriterLock seem to be really well written, and works on Mono + should be compatible with .NET core in the future, so we should go for it as it's the best bet both performance-wise and memory-wise.
This brings another package dependency and changes a bit backend of ConcurrentHashSet
142 lines
9.6 KiB
XML
142 lines
9.6 KiB
XML
<?xml version="1.0"?>
|
|
<doc>
|
|
<assembly>
|
|
<name>Microsoft.Threading.Tasks.Extensions.Silverlight</name>
|
|
</assembly>
|
|
<members>
|
|
<member name="T:AsyncPlatformExtensions">
|
|
<summary>
|
|
Provides asynchronous wrappers for .NET Framework operations.
|
|
</summary>
|
|
<summary>
|
|
Provides asynchronous wrappers for .NET Framework operations.
|
|
</summary>
|
|
</member>
|
|
<member name="M:AsyncPlatformExtensions.DownloadStringTaskAsync(System.Net.WebClient,System.String)">
|
|
<summary>Downloads the resource with the specified URI as a string, asynchronously.</summary>
|
|
<param name="webClient">The WebClient.</param>
|
|
<param name="address">The URI from which to download data.</param>
|
|
<returns>A Task that contains the downloaded string.</returns>
|
|
</member>
|
|
<member name="M:AsyncPlatformExtensions.DownloadStringTaskAsync(System.Net.WebClient,System.Uri)">
|
|
<summary>Downloads the resource with the specified URI as a string, asynchronously.</summary>
|
|
<param name="webClient">The WebClient.</param>
|
|
<param name="address">The URI from which to download data.</param>
|
|
<returns>A Task that contains the downloaded string.</returns>
|
|
</member>
|
|
<member name="M:AsyncPlatformExtensions.OpenReadTaskAsync(System.Net.WebClient,System.String)">
|
|
<summary>Opens a readable stream for the data downloaded from a resource, asynchronously.</summary>
|
|
<param name="webClient">The WebClient.</param>
|
|
<param name="address">The URI for which the stream should be opened.</param>
|
|
<returns>A Task that contains the opened stream.</returns>
|
|
</member>
|
|
<member name="M:AsyncPlatformExtensions.OpenReadTaskAsync(System.Net.WebClient,System.Uri)">
|
|
<summary>Opens a readable stream for the data downloaded from a resource, asynchronously.</summary>
|
|
<param name="webClient">The WebClient.</param>
|
|
<param name="address">The URI for which the stream should be opened.</param>
|
|
<returns>A Task that contains the opened stream.</returns>
|
|
</member>
|
|
<member name="M:AsyncPlatformExtensions.OpenWriteTaskAsync(System.Net.WebClient,System.String)">
|
|
<summary>Opens a writeable stream for uploading data to a resource, asynchronously.</summary>
|
|
<param name="webClient">The WebClient.</param>
|
|
<param name="address">The URI for which the stream should be opened.</param>
|
|
<returns>A Task that contains the opened stream.</returns>
|
|
</member>
|
|
<member name="M:AsyncPlatformExtensions.OpenWriteTaskAsync(System.Net.WebClient,System.Uri)">
|
|
<summary>Opens a writeable stream for uploading data to a resource, asynchronously.</summary>
|
|
<param name="webClient">The WebClient.</param>
|
|
<param name="address">The URI for which the stream should be opened.</param>
|
|
<returns>A Task that contains the opened stream.</returns>
|
|
</member>
|
|
<member name="M:AsyncPlatformExtensions.OpenWriteTaskAsync(System.Net.WebClient,System.String,System.String)">
|
|
<summary>Opens a writeable stream for uploading data to a resource, asynchronously.</summary>
|
|
<param name="webClient">The WebClient.</param>
|
|
<param name="address">The URI for which the stream should be opened.</param>
|
|
<param name="method">The HTTP method that should be used to open the stream.</param>
|
|
<returns>A Task that contains the opened stream.</returns>
|
|
</member>
|
|
<member name="M:AsyncPlatformExtensions.OpenWriteTaskAsync(System.Net.WebClient,System.Uri,System.String)">
|
|
<summary>Opens a writeable stream for uploading data to a resource, asynchronously.</summary>
|
|
<param name="webClient">The WebClient.</param>
|
|
<param name="address">The URI for which the stream should be opened.</param>
|
|
<param name="method">The HTTP method that should be used to open the stream.</param>
|
|
<returns>A Task that contains the opened stream.</returns>
|
|
</member>
|
|
<member name="M:AsyncPlatformExtensions.UploadStringTaskAsync(System.Net.WebClient,System.String,System.String)">
|
|
<summary>Uploads data in a string to the specified resource, asynchronously.</summary>
|
|
<param name="webClient">The WebClient.</param>
|
|
<param name="address">The URI to which the data should be uploaded.</param>
|
|
<param name="data">The data to upload.</param>
|
|
<returns>A Task containing the data in the response from the upload.</returns>
|
|
</member>
|
|
<member name="M:AsyncPlatformExtensions.UploadStringTaskAsync(System.Net.WebClient,System.Uri,System.String)">
|
|
<summary>Uploads data in a string to the specified resource, asynchronously.</summary>
|
|
<param name="webClient">The WebClient.</param>
|
|
<param name="address">The URI to which the data should be uploaded.</param>
|
|
<param name="data">The data to upload.</param>
|
|
<returns>A Task containing the data in the response from the upload.</returns>
|
|
</member>
|
|
<member name="M:AsyncPlatformExtensions.UploadStringTaskAsync(System.Net.WebClient,System.String,System.String,System.String)">
|
|
<summary>Uploads data in a string to the specified resource, asynchronously.</summary>
|
|
<param name="webClient">The WebClient.</param>
|
|
<param name="address">The URI to which the data should be uploaded.</param>
|
|
<param name="method">The HTTP method that should be used to upload the data.</param>
|
|
<param name="data">The data to upload.</param>
|
|
<returns>A Task containing the data in the response from the upload.</returns>
|
|
</member>
|
|
<member name="M:AsyncPlatformExtensions.UploadStringTaskAsync(System.Net.WebClient,System.Uri,System.String,System.String)">
|
|
<summary>Uploads data in a string to the specified resource, asynchronously.</summary>
|
|
<param name="webClient">The WebClient.</param>
|
|
<param name="address">The URI to which the data should be uploaded.</param>
|
|
<param name="method">The HTTP method that should be used to upload the data.</param>
|
|
<param name="data">The data to upload.</param>
|
|
<returns>A Task containing the data in the response from the upload.</returns>
|
|
</member>
|
|
<member name="M:AsyncPlatformExtensions.GetUri(System.Net.WebClient,System.String)">
|
|
<summary>Converts a path to a Uri using the WebClient's logic.</summary>
|
|
<remarks>Based on WebClient's private GetUri method.</remarks>
|
|
</member>
|
|
<member name="M:AsyncPlatformExtensions.GetUri(System.Net.WebClient,System.Uri)">
|
|
<summary>Converts a path to a Uri using the WebClient's logic.</summary>
|
|
<remarks>Based on WebClient's private GetUri method.</remarks>
|
|
</member>
|
|
<member name="M:AsyncPlatformExtensions.InvokeAsync(System.Windows.Threading.Dispatcher,System.Action)">
|
|
<summary>Asynchronously invokes an Action on the Dispatcher.</summary>
|
|
<param name="dispatcher">The Dispatcher.</param>
|
|
<param name="action">The action to invoke.</param>
|
|
<returns>A Task that represents the execution of the action.</returns>
|
|
</member>
|
|
<member name="M:AsyncPlatformExtensions.InvokeAsync``1(System.Windows.Threading.Dispatcher,System.Func{``0})">
|
|
<summary>Asynchronously invokes an Action on the Dispatcher.</summary>
|
|
<param name="dispatcher">The Dispatcher.</param>
|
|
<param name="function">The function to invoke.</param>
|
|
<returns>A Task that represents the execution of the function.</returns>
|
|
</member>
|
|
<member name="M:System.Threading.Tasks.TaskServices.FromCancellation(System.Threading.CancellationToken)">
|
|
<summary>Returns a canceled task.</summary>
|
|
<param name="cancellationToken">The cancellation token.</param>
|
|
<returns>The canceled task.</returns>
|
|
</member>
|
|
<member name="M:System.Threading.Tasks.TaskServices.FromCancellation``1(System.Threading.CancellationToken)">
|
|
<summary>Returns a canceled task.</summary>
|
|
<typeparam name="TResult">Specifies the type of the result.</typeparam>
|
|
<param name="cancellationToken">The cancellation token.</param>
|
|
<returns>The canceled task.</returns>
|
|
</member>
|
|
<member name="M:System.Threading.Tasks.TaskServices.HandleEapCompletion``1(System.Threading.Tasks.TaskCompletionSource{``0},System.Boolean,System.ComponentModel.AsyncCompletedEventArgs,System.Func{``0},System.Action)">
|
|
<summary>
|
|
Completes the Task if the user state matches the TaskCompletionSource.
|
|
</summary>
|
|
<typeparam name="T">Specifies the type of data returned by the Task.</typeparam>
|
|
<param name="tcs">The TaskCompletionSource.</param>
|
|
<param name="e">The completion event arguments.</param>
|
|
<param name="requireMatch">Whether we require the tcs to match the e.UserState.</param>
|
|
<param name="getResult">A function that gets the result with which to complete the task.</param>
|
|
<param name="unregisterHandler">An action used to unregister work when the operaiton completes.</param>
|
|
</member>
|
|
<member name="T:VoidTaskResult">
|
|
<summary>Used with Task(of void)</summary>
|
|
</member>
|
|
</members>
|
|
</doc>
|