Здравствуйте, samius, Вы писали:
S>Воткните ка перед ReadLine слип, а то он походу блокирует консоль от вывода на нее WriteLine-ов из другого потока (на правах предположения).
Переписал с Debug.WriteLine -- разницы нет. Поток только один (см. код ниже).
class Program
{
static readonly AsyncLock al = new AsyncLock();
static bool called = false;
static void Main(string[] args)
{
AsyncCaller();
Console.ReadLine();
}
static async void AsyncCaller()
{
await DoItAsync();
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());
Debug.WriteLine("Done");
}
static async Task DoItAsync()
{
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());
Debug.WriteLine("before lock");
using (await al.LockAsync())
{
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());
Debug.WriteLine("after lock"); // Не вызывается второй раз!!!if (!called)
{
called = true;
await DoItAsync();
}
}
}
}
Здравствуйте, IObserver, Вы писали:
IO>Здравствуйте, samius, Вы писали:
S>>Воткните ка перед ReadLine слип, а то он походу блокирует консоль от вывода на нее WriteLine-ов из другого потока (на правах предположения).
IO>Переписал с Debug.WriteLine -- разницы нет. Поток только один (см. код ниже).
Посмотрел код, все согласно AsyncSemaphore -у. Первый вызов WaitAsync пропускает, второй без релиза ставится в очередь. Никакой проверки, тот же поток или не тот же нет, т.е. поведение будет отличаться от Monitor.Enter.
Здравствуйте, samius, Вы писали:
S>Посмотрел код, все согласно AsyncSemaphore -у. Первый вызов WaitAsync пропускает, второй без релиза ставится в очередь. Никакой проверки, тот же поток или не тот же нет, т.е. поведение будет отличаться от Monitor.Enter.
Вот и я о том же -- реализация не корректна. Хотя вроде один из MS-овцев писал -- неужели таких вещей не знает.
Здравствуйте, IObserver, Вы писали:
IO>Здравствуйте, samius, Вы писали:
S>>Посмотрел код, все согласно AsyncSemaphore -у. Первый вызов WaitAsync пропускает, второй без релиза ставится в очередь. Никакой проверки, тот же поток или не тот же нет, т.е. поведение будет отличаться от Monitor.Enter.
IO>Вот и я о том же -- реализация не корректна. Хотя вроде один из MS-овцев писал -- неужели таких вещей не знает.
Он же не продакшн писал, чисто идеи.
IO>Где брать правильное или чем заменить?
Правильное, боюсь, нетривиально. Нужно чем-то помечать "нити" выполнения и уметь узнавать их, с оглядкой на то что псевдонити будут выполняться различными потоками (последовательно). Т.е. всякие TLS для хранения метки идут лесом.
Получается что псевдонить должна получать какой-то идентификатор и передавать его в Lock, что бы там можно было сверить с тем, кто уже захватил ресурс. Этот идентификатор надо будет передавать во вложенные await методы.
Не очень красиво, но работать будет. Возможно стоит пересмотреть логику и хранить признак захвата где-то в клиентском коде (т.е. не в коде AsyncLocker-а).
One important point is that this class does not support reentrancy the way the Monitor class (or C# lock keyword) does. So in that respect it's more like an AsyncSemaphore that's fixed at concurrency level 1. Since this class returns an IDisposable releaser, I prefer this class to the last post's semaphore class.
В общем случае я бы поостерёгся использовать блокирующие примитивы вместе с тасками/async, очень уж легко нарваться на вечную блокировку. Тем более — позаимствовав наброски из блога, которые просто демонстрируют идею, и как-то не похожи на production-ready код