mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2026-01-01 06:00:46 +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
16 lines
1.1 KiB
XML
16 lines
1.1 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<packages>
|
|
<package id="Costura.Fody" version="2.0.0-beta0018" targetFramework="net461" developmentDependency="true" />
|
|
<package id="Fody" version="1.30.0-beta01" targetFramework="net461" developmentDependency="true" />
|
|
<package id="HtmlAgilityPack" version="1.4.9.5" targetFramework="net461" />
|
|
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="net461" />
|
|
<package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net461" />
|
|
<package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net461" />
|
|
<package id="Newtonsoft.Json" version="9.0.2-beta2" targetFramework="net461" />
|
|
<package id="Nito.AsyncEx" version="4.0.1" targetFramework="net461" />
|
|
<package id="NLog" version="5.0.0-beta05-test" targetFramework="net461" />
|
|
<package id="NLog.Windows.Forms" version="4.2.3" targetFramework="net461" />
|
|
<package id="protobuf-net" version="2.0.0.668" targetFramework="net461" />
|
|
<package id="Resource.Embedder" version="1.2.2" targetFramework="net461" developmentDependency="true" />
|
|
<package id="SteamKit2" version="1.8.0" targetFramework="net461" />
|
|
</packages> |