Maison >développement back-end >C++ >Comment éviter les erreurs d'accès intermittent aux fichiers avec le verrouillage asynchrone en C# ?

Comment éviter les erreurs d'accès intermittent aux fichiers avec le verrouillage asynchrone en C# ?

Patricia Arquette
Patricia Arquetteoriginal
2025-01-15 06:03:44815parcourir

How to Avoid Intermittent File Access Errors with Asynchronous Locking in C#?

Résolution des erreurs d'accès intermittent aux fichiers avec le verrouillage asynchrone en C#

Le verrouillage asynchrone, en particulier lors de l'utilisation d'une URL hachée et d'une classe comme AsyncDuplicateLock, peut parfois entraîner des erreurs intermittentes d'accès aux fichiers. Cela provient souvent d'une mauvaise gestion des sémaphores dans un dictionnaire concurrent. Une première approche erronée pourrait ressembler à ceci :

<code class="language-csharp">SemaphoreSlim locker;
if (SemaphoreSlims.TryRemove(s, out locker))
{
    locker.Release();
    locker.Dispose();
}</code>

Le problème ici est de supprimer le sémaphore avant de le libérer. Cela crée un roulement excessif des sémaphores, conduisant à une utilisation continue du sémaphore même après sa suppression du dictionnaire.

Une solution robuste utilise le comptage de références pour gérer la durée de vie des sémaphores :

<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>

Ce code révisé utilise un RefCounted<T> wrapper pour suivre les références de sémaphore. Un sémaphore n'est supprimé du dictionnaire que lorsque son nombre de références atteint zéro, garantissant une libération correcte et empêchant une suppression prématurée, éliminant ainsi 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!

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