Maison >développement back-end >C++ >Comment implémenter correctement le verrouillage asynchrone à l'aide de SemaphoreSlim pour éviter les erreurs d'accès intermittent aux fichiers ?
La bibliothèque ImageProcessor a récemment rencontré des erreurs intermittentes d'accès aux fichiers lors des mises à jour du cache, dues à un verrouillage asynchrone défectueux. Cet article analyse l'implémentation défectueuse d'origine et fournit une solution robuste.
L'approche originale utilisait des URL hachées comme clés pour les verrous asynchrones, stockant les instances SemaphoreSlim
dans un ConcurrentDictionary
pour garantir un verrouillage à clé unique. Le défaut critique résidait dans la suppression synchrone du SemaphoreSlim
du dictionnaire avant de libérer le sémaphore. Cette condition de concurrence a conduit à des conflits d'accès aux fichiers.
L'extrait de code suivant illustre le référencement de clé/SemaphoreSlim
problématique :
<code class="language-csharp">private static readonly Dictionary<object, RefCounted<SemaphoreSlim>> SemaphoreSlims = new Dictionary<object, RefCounted<SemaphoreSlim>>(); private SemaphoreSlim GetOrCreate(object key) { RefCounted<SemaphoreSlim> item; lock (SemaphoreSlims) { if (SemaphoreSlims.TryGetValue(key, out item)) { ++item.RefCount; } else { item = new RefCounted<SemaphoreSlim>(new SemaphoreSlim(1, 1)); SemaphoreSlims[key] = item; } } return item.Value; }</code>
Ci-dessous se trouve la classe AsyncDuplicateLock
corrigée, résolvant le problème de concurrence :
<code class="language-csharp">public sealed class AsyncDuplicateLock { private sealed class RefCounted<T> { public RefCounted(T value) { RefCount = 1; Value = value; } public int RefCount { get; set; } public T Value { get; private set; } } private static readonly Dictionary<object, RefCounted<SemaphoreSlim>> SemaphoreSlims = new Dictionary<object, RefCounted<SemaphoreSlim>>(); private SemaphoreSlim GetOrCreate(object key) { RefCounted<SemaphoreSlim> item; lock (SemaphoreSlims) { if (SemaphoreSlims.TryGetValue(key, out item)) { ++item.RefCount; } else { item = new RefCounted<SemaphoreSlim>(new SemaphoreSlim(1, 1)); SemaphoreSlims[key] = item; } } return item.Value; } public IDisposable Lock(object key) { GetOrCreate(key).Wait(); return new Releaser { Key = key }; } public async Task<IDisposable> LockAsync(object key) { await GetOrCreate(key).WaitAsync().ConfigureAwait(false); return new Releaser { Key = key }; } private sealed class Releaser : IDisposable { public object Key { get; set; } public void Dispose() { RefCounted<SemaphoreSlim> item; lock (SemaphoreSlims) { item = SemaphoreSlims[Key]; --item.RefCount; if (item.RefCount == 0) SemaphoreSlims.Remove(Key); } item.Value.Release(); } } }</code>
Cette implémentation révisée garantit que le sémaphore est publié avant la suppression du dictionnaire, éliminant ainsi la condition de concurrence critique et résolvant les erreurs intermittentes d'accès aux fichiers.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!