РЕДАКТИРОВАТЬ: я обновил мои примеры для использования библиотеки https://github.com/StephenCleary/AsyncEx. Все еще ждут полезных подсказок.
Есть ресурсы, которые идентифицируются строками (например, файлы, URL-адреса и т. Д. c.). Я ищу механизм блокировки ресурсов. Я нашел 2 разных решения, но у каждого есть свои проблемы:
Первый использует класс ConcurrentDictionary
с AsyncLock
:
using Nito.AsyncEx;
using System.Collections.Concurrent;
internal static class Locking {
private static ConcurrentDictionary<string, AsyncLock> mutexes
= new ConcurrentDictionary<string, AsyncLock>();
internal static AsyncLock GetMutex(string resourceLocator) {
return mutexes.GetOrAdd(
resourceLocator,
key => new AsyncLock()
);
}
}
Asyn c использование:
using (await Locking.GetMutex("resource_string").LockAsync()) {
...
}
Синхронное использование:
using (Locking.GetMutex("resource_string").Lock()) {
...
}
Это работает безопасно, но проблема в том, что словарь становится все больше и больше, и я не вижу поточно-безопасный способ удаления элементов из словаря, когда никто не ждет блокировки. (Я также хочу избежать глобальных блокировок.)
Мое второе решение хэширует строку с числом от 0
до N - 1
и фиксирует на них:
using Nito.AsyncEx;
using System.Collections.Concurrent;
internal static class Locking {
private const UInt32 BUCKET_COUNT = 4096;
private static ConcurrentDictionary<UInt32, AsyncLock> mutexes
= new ConcurrentDictionary<UInt32, AsyncLock>();
private static UInt32 HashStringToInt(string text) {
return ((UInt32)text.GetHashCode()) % BUCKET_COUNT;
}
internal static AsyncLock GetMutex(string resourceLocator) {
return mutexes.GetOrAdd(
HashStringToInt(resourceLocator),
key => new AsyncLock()
);
}
}
как единое целое Как видно, второе решение только уменьшает вероятность столкновений, но не избегает их. Больше всего я боюсь, что это может привести к взаимоблокировкам. Основная стратегия, позволяющая избежать взаимоблокировок, - это всегда блокировать элементы в определенном порядке c. Но при таком подходе разные элементы могут отображаться в одни и те же сегменты в разном порядке, например: (A-> X, B-> Y), (C -> Y, D-> X). Таким образом, с этим решением нельзя безопасно заблокировать более одного ресурса.
Есть ли лучшее решение? (Я также приветствую критику вышеупомянутых 2 решений.)