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
276 lines
19 KiB
XML
276 lines
19 KiB
XML
<?xml version="1.0"?>
|
|
<doc>
|
|
<assembly>
|
|
<name>Microsoft.Threading.Tasks.Extensions</name>
|
|
</assembly>
|
|
<members>
|
|
<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:AsyncExtensions">
|
|
<summary>
|
|
Provides asynchronous wrappers for .NET Framework operations.
|
|
</summary>
|
|
</member>
|
|
<member name="M:AsyncExtensions.ReadAsync(System.IO.Stream,System.Byte[],System.Int32,System.Int32)">
|
|
<summary>
|
|
Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
|
|
</summary>
|
|
<returns>A Task that represents the asynchronous read.</returns>
|
|
<param name="source">The source.</param>
|
|
<param name="buffer">The buffer to read data into. </param>
|
|
<param name="offset">The byte offset in at which to begin reading. </param>
|
|
<param name="count">The maximum number of bytes to read. </param>
|
|
<exception cref="T:System.ArgumentException">The array length minus is less than <paramref name="count" />. </exception>
|
|
<exception cref="T:System.ArgumentNullException"> is null. </exception>
|
|
<exception cref="T:System.ArgumentOutOfRangeException"> or <paramref name="count" /> is negative. </exception>
|
|
<exception cref="T:System.IO.IOException">An asynchronous read was attempted past the end of the file. </exception>
|
|
</member>
|
|
<member name="M:AsyncExtensions.ReadAsync(System.IO.Stream,System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken)">
|
|
<summary>
|
|
Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
|
|
</summary>
|
|
<returns>A Task that represents the asynchronous read.</returns>
|
|
<param name="source">The source.</param>
|
|
<param name="buffer">The buffer to read data into. </param>
|
|
<param name="offset">The byte offset in at which to begin reading. </param>
|
|
<param name="count">The maximum number of bytes to read. </param>
|
|
<param name="cancellationToken">The cancellation token.</param>
|
|
<exception cref="T:System.ArgumentException">The array length minus is less than <paramref name="count" />. </exception>
|
|
<exception cref="T:System.ArgumentNullException"> is null. </exception>
|
|
<exception cref="T:System.ArgumentOutOfRangeException"> or <paramref name="count" /> is negative. </exception>
|
|
<exception cref="T:System.IO.IOException">An asynchronous read was attempted past the end of the file. </exception>
|
|
</member>
|
|
<member name="M:AsyncExtensions.WriteAsync(System.IO.Stream,System.Byte[],System.Int32,System.Int32)">
|
|
<summary>
|
|
Writes asynchronously a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written.
|
|
</summary>
|
|
<returns>A Task that represents the asynchronous write.</returns>
|
|
<param name="source">The source.</param>
|
|
<param name="buffer">The buffer containing data to write to the current stream.</param>
|
|
<param name="offset">The zero-based byte offset in at which to begin copying bytes to the current stream.</param>
|
|
<param name="count">The maximum number of bytes to write. </param>
|
|
<exception cref="T:System.ArgumentException"> length minus <paramref name="offset" /> is less than <paramref name="count" />. </exception>
|
|
<exception cref="T:System.ArgumentNullException"> is null. </exception>
|
|
<exception cref="T:System.ArgumentOutOfRangeException"> or <paramref name="count" /> is negative. </exception>
|
|
<exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>
|
|
<exception cref="T:System.ObjectDisposedException">The stream is closed. </exception>
|
|
<exception cref="T:System.IO.IOException">An I/O error occurred. </exception>
|
|
</member>
|
|
<member name="M:AsyncExtensions.WriteAsync(System.IO.Stream,System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken)">
|
|
<summary>
|
|
Writes asynchronously a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written.
|
|
</summary>
|
|
<returns>A Task that represents the asynchronous write.</returns>
|
|
<param name="source">The source.</param>
|
|
<param name="buffer">The buffer containing data to write to the current stream.</param>
|
|
<param name="offset">The zero-based byte offset in at which to begin copying bytes to the current stream.</param>
|
|
<param name="count">The maximum number of bytes to write. </param>
|
|
<param name="cancellationToken">The cancellation token.</param>
|
|
<exception cref="T:System.ArgumentException"> length minus <paramref name="offset" /> is less than <paramref name="count" />. </exception>
|
|
<exception cref="T:System.ArgumentNullException"> is null. </exception>
|
|
<exception cref="T:System.ArgumentOutOfRangeException"> or <paramref name="count" /> is negative. </exception>
|
|
<exception cref="T:System.NotSupportedException">The stream does not support writing. </exception>
|
|
<exception cref="T:System.ObjectDisposedException">The stream is closed. </exception>
|
|
<exception cref="T:System.IO.IOException">An I/O error occurred. </exception>
|
|
</member>
|
|
<member name="M:AsyncExtensions.FlushAsync(System.IO.Stream)">
|
|
<summary>
|
|
Flushes asynchronously the current stream.
|
|
</summary>
|
|
<returns>A Task that represents the asynchronous flush.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.FlushAsync(System.IO.Stream,System.Threading.CancellationToken)">
|
|
<summary>
|
|
Flushes asynchronously the current stream.
|
|
</summary>
|
|
<returns>A Task that represents the asynchronous flush.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.CopyToAsync(System.IO.Stream,System.IO.Stream)">
|
|
<summary>
|
|
Reads all the bytes from the current stream and writes them to the destination stream.
|
|
</summary>
|
|
<param name="source">The source stream.</param>
|
|
<param name="destination">The stream that will contain the contents of the current stream.</param>
|
|
<returns>A Task that represents the asynchronous operation.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.CopyToAsync(System.IO.Stream,System.IO.Stream,System.Int32)">
|
|
<summary>
|
|
Reads all the bytes from the current stream and writes them to the destination stream.
|
|
</summary>
|
|
<param name="source">The source stream.</param>
|
|
<param name="destination">The stream that will contain the contents of the current stream.</param>
|
|
<param name="bufferSize">The size of the buffer. This value must be greater than zero. The default size is 4096.</param>
|
|
<returns>A Task that represents the asynchronous operation.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.CopyToAsync(System.IO.Stream,System.IO.Stream,System.Int32,System.Threading.CancellationToken)">
|
|
<summary>
|
|
Reads all the bytes from the current stream and writes them to the destination stream.
|
|
</summary>
|
|
<param name="source">The source stream.</param>
|
|
<param name="destination">The stream that will contain the contents of the current stream.</param>
|
|
<param name="bufferSize">The size of the buffer. This value must be greater than zero. The default size is 4096.</param>
|
|
<param name="cancellationToken">The cancellation token to use to cancel the asynchronous operation.</param>
|
|
<returns>A Task that represents the asynchronous operation.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.CopyToAsyncInternal(System.IO.Stream,System.IO.Stream,System.Int32,System.Threading.CancellationToken)">
|
|
<summary>
|
|
Reads all the bytes from the current stream and writes them to the destination stream.
|
|
</summary>
|
|
<param name="source">The source stream.</param>
|
|
<param name="destination">The stream that will contain the contents of the current stream.</param>
|
|
<param name="bufferSize">The size of the buffer. This value must be greater than zero. The default size is 4096.</param>
|
|
<param name="cancellationToken">The cancellation token to use to cancel the asynchronous operation.</param>
|
|
<returns>A Task that represents the asynchronous operation.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.ReadAsync(System.IO.TextReader,System.Char[],System.Int32,System.Int32)">
|
|
<summary>
|
|
Reads a maximum of count characters from the reader asynchronously and writes
|
|
the data to buffer, beginning at index.
|
|
</summary>
|
|
<param name="buffer">
|
|
When the operation completes, contains the specified character array with the
|
|
values between index and (index + count - 1) replaced by the characters read
|
|
from the current source.
|
|
</param>
|
|
<param name="count">
|
|
The maximum number of characters to read. If the end of the stream is reached
|
|
before count of characters is read into buffer, the current method returns.
|
|
</param>
|
|
<param name="index">The place in buffer at which to begin writing.</param>
|
|
<param name="source">the source reader.</param>
|
|
<returns>A Task that represents the asynchronous operation.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.ReadBlockAsync(System.IO.TextReader,System.Char[],System.Int32,System.Int32)">
|
|
<summary>
|
|
Reads asynchronously a maximum of count characters from the current stream, and writes the
|
|
data to buffer, beginning at index.
|
|
</summary>
|
|
<param name="source">The source reader.</param>
|
|
<param name="buffer">
|
|
When this method returns, this parameter contains the specified character
|
|
array with the values between index and (index + count -1) replaced by the
|
|
characters read from the current source.
|
|
</param>
|
|
<param name="index">The position in buffer at which to begin writing.</param>
|
|
<param name="count">The maximum number of characters to read.</param>
|
|
<returns>A Task that represents the asynchronous operation.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.ReadLineAsync(System.IO.TextReader)">
|
|
<summary>
|
|
Reads a line of characters from the reader and returns the string asynchronously.
|
|
</summary>
|
|
<param name="source">the source reader.</param>
|
|
<returns>A Task that represents the asynchronous operation.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.ReadToEndAsync(System.IO.TextReader)">
|
|
<summary>
|
|
Reads all characters from the current position to the end of the TextReader
|
|
and returns them as one string asynchronously.
|
|
</summary>
|
|
<param name="source">the source reader.</param>
|
|
<returns>A Task that represents the asynchronous operation.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.WriteAsync(System.IO.TextWriter,System.String)">
|
|
<summary>Writes a string asynchronously to a text stream.</summary>
|
|
<param name="target">The writer.</param>
|
|
<param name="value">The string to write.</param>
|
|
<returns>A Task representing the asynchronous write.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.WriteAsync(System.IO.TextWriter,System.Char)">
|
|
<summary>Writes a char asynchronously to a text stream.</summary>
|
|
<param name="target">The writer.</param>
|
|
<param name="value">The char to write.</param>
|
|
<returns>A Task representing the asynchronous write.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.WriteAsync(System.IO.TextWriter,System.Char[])">
|
|
<summary>Writes a char array asynchronously to a text stream.</summary>
|
|
<param name="target">The writer.</param>
|
|
<param name="buffer">The buffer to write.</param>
|
|
<returns>A Task representing the asynchronous write.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.WriteAsync(System.IO.TextWriter,System.Char[],System.Int32,System.Int32)">
|
|
<summary>Writes a subarray of characters asynchronously to a text stream.</summary>
|
|
<param name="target">The writer.</param>
|
|
<param name="buffer">The buffer to write.</param>
|
|
<param name="index">Starting index in the buffer.</param>
|
|
<param name="count">The number of characters to write.</param>
|
|
<returns>A Task representing the asynchronous write.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.WriteLineAsync(System.IO.TextWriter)">
|
|
<summary>Writes a line terminator asynchronously to a text stream.</summary>
|
|
<param name="target">The writer.</param>
|
|
<returns>A Task representing the asynchronous write.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.WriteLineAsync(System.IO.TextWriter,System.String)">
|
|
<summary>Writes a string followed by a line terminator asynchronously to a text stream.</summary>
|
|
<param name="target">The writer.</param>
|
|
<param name="value">The string to write.</param>
|
|
<returns>A Task representing the asynchronous write.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.WriteLineAsync(System.IO.TextWriter,System.Char)">
|
|
<summary>Writes a char followed by a line terminator asynchronously to a text stream.</summary>
|
|
<param name="target">The writer.</param>
|
|
<param name="value">The char to write.</param>
|
|
<returns>A Task representing the asynchronous write.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.WriteLineAsync(System.IO.TextWriter,System.Char[])">
|
|
<summary>Writes a char array followed by a line terminator asynchronously to a text stream.</summary>
|
|
<param name="target">The writer.</param>
|
|
<param name="buffer">The buffer to write.</param>
|
|
<returns>A Task representing the asynchronous write.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.WriteLineAsync(System.IO.TextWriter,System.Char[],System.Int32,System.Int32)">
|
|
<summary>Writes a subarray of characters followed by a line terminator asynchronously to a text stream.</summary>
|
|
<param name="target">The writer.</param>
|
|
<param name="buffer">The buffer to write.</param>
|
|
<param name="index">Starting index in the buffer.</param>
|
|
<param name="count">The number of characters to write.</param>
|
|
<returns>A Task representing the asynchronous write.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.FlushAsync(System.IO.TextWriter)">
|
|
<summary>
|
|
Clears all buffers for the current writer and causes any buffered data to
|
|
be written to the underlying device.
|
|
</summary>
|
|
<param name="target">The writer.</param>
|
|
<returns>A Task representing the asynchronous flush.</returns>
|
|
</member>
|
|
<member name="M:AsyncExtensions.GetResponseAsync(System.Net.WebRequest)">
|
|
<summary>Starts an asynchronous request for a web resource.</summary>
|
|
<returns>Task that represents the asynchronous request.</returns>
|
|
<exception cref="T:System.InvalidOperationException">The stream is already in use by a previous call to . </exception>
|
|
<PermissionSet> <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" /> </PermissionSet>
|
|
<param name="source">The source.</param>
|
|
</member>
|
|
<member name="M:AsyncExtensions.GetRequestStreamAsync(System.Net.WebRequest)">
|
|
<summary>Starts an asynchronous request for a object to use to write data.</summary>
|
|
<returns>Task that represents the asynchronous request.</returns>
|
|
<exception cref="T:System.Net.ProtocolViolationException">The property is GET and the application writes to the stream. </exception>
|
|
<exception cref="T:System.InvalidOperationException">The stream is being used by a previous call to . </exception>
|
|
<exception cref="T:System.ApplicationException">No write stream is available. </exception>
|
|
<PermissionSet> <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" /> </PermissionSet>
|
|
<param name="source">The source.</param>
|
|
</member>
|
|
</members>
|
|
</doc>
|