Rumah >pembangunan bahagian belakang >C++ >Mengapakah penguncian tak segerak berdasarkan kunci menyebabkan ralat capaian fail terputus-putus, dan bagaimanakah pendekatan pengiraan rujukan boleh memperbaikinya?

Mengapakah penguncian tak segerak berdasarkan kunci menyebabkan ralat capaian fail terputus-putus, dan bagaimanakah pendekatan pengiraan rujukan boleh memperbaikinya?

Susan Sarandon
Susan Sarandonasal
2025-01-15 09:35:43239semak imbas

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

Penguncian Berasaskan Kunci Tak Segerak: Sumber Ralat Akses Fail Berselang-seli

Mekanisme cache pustaka ImageProcessor, menggunakan penguncian tak segerak berdasarkan kekunci, mengalami ralat akses fail yang terputus-putus. Ini berpunca daripada kecacatan reka bentuk dalam kelas AsyncDuplicateLock.

Kecacatan: Pelepasan Semaphore Pramatang

Kod AsyncDuplicateLock asal mengalih keluar tika SemaphoreSlim daripada ConcurrentDictionary sebelum mengeluarkan semaphore. Ini membawa kepada churn semaphore yang berlebihan dan kemungkinan ralat kerana semaphore mungkin boleh diakses selepas dialih keluar.

Penyelesaian: Pendekatan Pengiraan Rujukan Teguh

Penyelesaian unggul menggunakan pengiraan rujukan. Setiap semafor dalam kamus mengekalkan kiraan rujukan. Kunci tunggal menjamin atomicity untuk mengurangkan kiraan dan mengeluarkan semafor, menghapuskan keperluan untuk 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>

Pendekatan yang disemak ini menjamin semaphore dikeluarkan hanya apabila tidak diperlukan lagi, dengan berkesan menghalang ralat akses fail terputus-putus semasa operasi cache.

Atas ialah kandungan terperinci Mengapakah penguncian tak segerak berdasarkan kunci menyebabkan ralat capaian fail terputus-putus, dan bagaimanakah pendekatan pengiraan rujukan boleh memperbaikinya?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn