Я извлекаю из класса System.Net.HttpClient
для реализации клиента, который обрабатывает извлечение токенов и обновление. Клиент инициализируется с использованием всех необходимых параметров аутентификации и может потенциально использоваться одновременно. В этом случае мне нужно запретить клиенту запрашивать несколько токенов (для разных запросов).Может ли использование Семафора в асинхронных методах привести к взаимоблокировкам в потоке диспетчера WPF?
Я не уверен, может ли мой код привести к тупиков в приложении WPF, если пользователь запускает несколько веб-запросов на диспетчерском нити (поскольку семафор неповторно, поэтому диспетчеру нить может быть заблокирован во время ожидания на семафоре, и исходная задача может не завершиться, если поток диспетчера заблокирован).
public class ApiClient : HttpClient
{
public override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (_token == null)
{
await _semaphore.WaitAsync(cancellationToken);
try
{
if (_token == null)
{
// _token = await _tokenService.AcquireToken(xx,xx,xx);
}
}
finally
{
_semaphore.Release();
}
}
else if (_token.IsExpired)
{
await _semaphore.WaitAsync(cancellationToken);
try
{
if (_token.IsExpired)
{
// _token = await _tokenService.RefreshToken(xx,xx,xx);
}
}
finally
{
_semaphore.Release();
}
}
return await base.SendAsync(request, cancellationToken);
}
}
Тупик возникает, когда есть 2 потока, ожидающих друг друга. Поэтому в основном, если ваш Dispatcher Thread ждет Api Thread (что на самом деле происходит) и Api Thread ждут ответа от Dispatcher Thread (это не должно быть так), тогда вы получите тупик. Я не понимаю, почему в вашем сценарии должен произойти тупик. В худшем случае будет тайм-аут, если запросов слишком много, а некоторым не удастся закончить со временем. – 3615
Но я определенно получаю тупик при использовании синхронного метода Wait() семафора, верно? – Ehssan
Я так не думаю. Если вы будете использовать Wait() вместо WaitAsync(), ситуация с взаимоблокировками не должна изменяться, если Api Thread каким-то скрытым способом попытается получить доступ к Dispatcher Thread. Разница была бы более неэффективным использованием потоков: ApplicationPool Task не вернется в пул, если семафор заполнен, но будет заблокирован. Поэтому, когда следующий запрос будет создан, заблокированный поток не сможет обслуживать запрос, и будет создан новый поток. Таким образом, вы получите гораздо больше потоков. – 3615