Раньше я использовал старый добрый lock(object) чтобы предотвратить доступ нескольких потоков к одной и той же части кода, например:
Код: Выделить всё
public class LazyLoadedItem
{
}
private LazyLoadedItem _item = null;
private readonly object MyLock = new object();
public LazyLoadedItem GetItem
{
get
{
{
if (_item != null)
return _item;
lock (MyLock)
{
// Serve the queue of threads that passed the first check when the floodgates opened...
if (_item != null)
return _item;
_item = new LazyLoadedItem(); // get from Database/FileSystem/Web
}
return _item;
}
}
}
public void ClearCache()
{
_item = null;
}
Однако... с наступлением эпохи await async блокировать таким образом было уже небезопасно, так как поток будет повторно использоваться, как только ему нужно будет дождаться базы данных/сети/файловой системы или чего-то еще. С тех пор я бы принял новый шаблон, используя SemaphoorSlim, чтобы обеспечить безопасную блокировку, например:
Код: Выделить всё
private readonly SemaphoreSlim MyLock = new SemaphoreSlim(1, 1);
public async Task GetItem(CancellationToken requestCancelled)
{
if (_item != null)
return _item;
await MyLock.WaitAsync(requestCancelled); // throws exception when cancelled
try
{
// Serve the queue of threads that passed the first check when the floodgates opened...
if (_item != null)
return _item;
_item = await GetLazyLoadedItem().ConfigureAwait(false); // get from Database/FileSystem/Web
// note that we may be continuing on a different thread here!
}
finally
{
MyLock.Release();
}
return _item;
}
В любом случае, мой вопрос о новом System.Threading.Lock заключается в том, где он подходит в? Это «асинхронно безопасно»?
Если нет, то я предполагаю, что его использование ограничено кодом, который никогда ничего не ожидает (например, вычисления кэширования, такие как общее количество * вес некоторой коллекции), что, на мой взгляд, сводит его вариант использования до такой малой величины, что внедрение в C#9 вряд ли оправдано. Единственное потенциальное применение, которое я могу придумать, — это кэширование отражения следующим образом:
Код: Выделить всё
private static Dictionary _props = null;
private static readonly System.Threading.Lock _myLock = new System.Threading.Lock();
public Dictionary Props
{
get
{
if (_props != null)
return _props;
lock (_myLock)
{
// Serve the queue of threads that passed the first check when the floodgates opened...
if (_props != null)
return _props;
_props = this.GetType().GetProperties().ToDictionary(p => p.Name);
}
return _props;
}
}
Так почему же был введен новый System.Threading.Lock ? Я полагаю, что в целом подавляющее большинство кода должно использовать SemaphoreSlim? Что мне не хватает?
Подробнее здесь: https://stackoverflow.com/questions/791 ... -9-introdu
Мобильная версия