Асинхронная блокировка на основе ключаC#

Место общения программистов C#
Ответить
Anonymous
 Асинхронная блокировка на основе ключа

Сообщение Anonymous »

Я пытаюсь выяснить проблему, возникшую в моей библиотеке ImageProcessor, из-за которой я периодически получаю ошибки доступа к файлу при добавлении элементов в кэш.


System.IO.IOException: процесс не может получить доступ к файлу 'D:\home\site\wwwroot\app_data\cache\0\6\5\f\2\7\065f27fc2c8e843443d210a1e84d1ea28bbab6c4.webp', потому что он используется другим процессом.


Я написал класс, предназначенный для выполнения асинхронной блокировки на основе ключа, сгенерированного хешированный URL-адрес, но, похоже, я что-то упустил в реализации.

Мой класс блокировки

Код: Выделить всё

public sealed class AsyncDuplicateLock
{
/// 
/// The collection of semaphore slims.
/// 
private static readonly ConcurrentDictionary SemaphoreSlims
= new ConcurrentDictionary();

/// 
/// Locks against the given key.
/// 
///
/// The key that identifies the current object.
/// 
/// 
/// The disposable .
/// 
public IDisposable Lock(object key)
{
DisposableScope releaser = new DisposableScope(
key,
s =>
{
SemaphoreSlim locker;
if (SemaphoreSlims.TryRemove(s, out locker))
{
locker.Release();
locker.Dispose();
}
});

SemaphoreSlim semaphore = SemaphoreSlims.GetOrAdd(key, new SemaphoreSlim(1, 1));
semaphore.Wait();
return releaser;
}

/// 
/// Asynchronously locks against the given key.
/// 
/// 
/// The key that identifies the current object.
/// 
/// 
/// The disposable .
/// 
public Task LockAsync(object key)
{
DisposableScope releaser = new DisposableScope(
key,
s =>
{
SemaphoreSlim locker;
if (SemaphoreSlims.TryRemove(s, out locker))
{
locker.Release();
locker.Dispose();
}
});

Task releaserTask = Task.FromResult(releaser as IDisposable);
SemaphoreSlim semaphore = SemaphoreSlims.GetOrAdd(key, new SemaphoreSlim(1, 1));

Task waitTask = semaphore.WaitAsync();

return waitTask.IsCompleted
? releaserTask
: waitTask.ContinueWith(
(_, r) => (IDisposable)r,
releaser,
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
}

/// 
/// The disposable scope.
/// 
private sealed class DisposableScope : IDisposable
{
/// 
/// The key
/// 
private readonly object key;

/// 
/// The close scope action.
/// 
private readonly Action closeScopeAction;

/// 
/// Initializes a new instance of the  class.
/// 
/// 
/// The key.
/// 
/// 
/// The close scope action.
/// 
public DisposableScope(object key, Action  closeScopeAction)
{
this.key = key;
this.closeScopeAction = closeScopeAction;
}

/// 
/// Disposes the scope.
/// 
public void Dispose()
{
this.closeScopeAction(this.key);
}
}
}
Использование — внутри HttpModule

Код: Выделить всё

private readonly AsyncDuplicateLock locker = new AsyncDuplicateLock();

using (await this.locker.LockAsync(cachedPath))
{
// Process and save a cached image.
}
Может ли кто-нибудь определить, где я ошибся? Меня беспокоит, что я неправильно понимаю что-то фундаментальное.

Полный исходный код библиотеки хранится на Github здесь

Подробнее здесь: https://stackoverflow.com/questions/311 ... d-on-a-key
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»