最近、ImageProcessor ライブラリで、非同期ロックの欠陥が原因で、キャッシュの更新中に断続的なファイル アクセス エラーが発生しました。この記事では、元の欠陥のある実装を分析し、堅牢な解決策を提供します。
元のアプローチでは、ハッシュ化された URL を非同期ロックのキーとして使用し、SemaphoreSlim
インスタンスを ConcurrentDictionary
に格納して、単一キーのロックを確保していました。 重大な欠陥は、セマフォを解放するSemaphoreSlim
前にを辞書から同期的に削除することにありました。この競合状態により、ファイル アクセスの競合が発生しました。
の参照を示しています。SemaphoreSlim
<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>以下は、同時実行の問題を解決した修正された
クラスです。AsyncDuplicateLock
<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>この改訂された実装により、ディクショナリから削除される
前にセマフォが解放されるようになり、競合状態が解消され、断続的なファイル アクセス エラーが解決されます。
以上が断続的なファイル アクセス エラーを防ぐために SemaphoreSlim を使用して非同期ロックを正しく実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。