Maison >développement back-end >C++ >Pourquoi le verrouillage asynchrone basé sur une clé provoque-t-il des erreurs intermittentes d'accès aux fichiers, et comment une approche de comptage de références peut-elle l'améliorer ?
Verrouillage asynchrone par clé : une source d'erreurs d'accès intermittent aux fichiers
Le mécanisme de cache de la bibliothèque ImageProcessor, utilisant un verrouillage asynchrone basé sur une clé, souffre d'erreurs intermittentes d'accès aux fichiers. Cela découle d'un défaut de conception au sein de la classe AsyncDuplicateLock
.
Le défaut : libération prématurée du sémaphore
Le code AsyncDuplicateLock
original supprime prématurément les instances SemaphoreSlim
du ConcurrentDictionary
avant de libérer le sémaphore. Cela entraîne un roulement excessif des sémaphores et des erreurs potentielles, car les sémaphores pourraient être accessibles après leur suppression.
Solution : une approche robuste de comptage de références
Une solution supérieure utilise le comptage de références. Chaque sémaphore du dictionnaire conserve un décompte de références. Un seul verrou garantit l'atomicité pour décrémenter le décompte et supprimer le sémaphore, éliminant ainsi le besoin d'un ConcurrentDictionary
.
<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 approche révisée garantit que les sémaphores ne sont libérés que lorsqu'ils ne sont plus nécessaires, empêchant ainsi les erreurs intermittentes d'accès aux fichiers lors des opérations de cache.
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!