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 ?

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 ?

Susan Sarandon
Susan Sarandonoriginal
2025-01-15 09:35:43245parcourir

Why does asynchronous locking based on a key cause intermittent file access errors, and how can a reference-counting approach improve it?

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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn