#c#
#c#
Вопрос:
private static bool Created;
private static System.Threading.Mutex PaintGuard = new System.Threading.Mutex(false, "MonkeysUncleBob", out Created);
//Function that is attached to each pages "LayoutUpdated" call.
private async void AnyPageLayoutUpdated(object sender, object e)
{
if (Created)
{
PaintGuard.WaitOne();
try
{
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
LCDDriver.ILI9488.PaintScreen(sender);
});
}
catch (Exception f)
{
}
finally
{
PaintGuard.ReleaseMutex();
}
}
}
Проблема в том, что каким-то образом несколько потоков все еще могут входить в код.
Я проверил это с помощью отладчика, и я вижу, что несколько потоков входят в попытку перед выполнением finally.
Должно быть, я использую его неправильно.
Комментарии:
1. Я просто размышляю, но это может быть проблемой повторного входа. Когда вы передаете управление диспетчеру (с помощью вашего
await
оператора), у вас нет абсолютно никакой гарантии, что поток пользовательского интерфейса не начнет выполнение другогоAnyPageLayoutUpdated
события до вызова отправленного вызова2. Более того, согласно MSDN, поток может получать один и тот же мьютекс несколько раз:
The thread that owns a mutex can request the same mutex in repeated calls to WaitOne without blocking its execution.
Итак, да, я думаю, что это все3. Откуда вы знаете, что это отдельные потоки, а не один и тот же поток? Я бы ожидал, что этот код позволит потоку пользовательского интерфейса выполнять другую работу, пока он ожидает результата от PaintScreen (предположительно, вы хотите , чтобы это вело себя так, чтобы пользовательский интерфейс не отображался как «зависший»).
4. Круто — я рад, что у всех нас была одна и та же идея для отказа. В чем тогда заключается исправление? Возможно, сбой и грязная блокировка bool?
5. @user1390652 Ну, зачем тебе блокировка для начала? Ваш код уже однопоточный
Ответ №1:
await
не совместим с Mutex
. Вы можете использовать асинхронно-совместимый мьютекс, например SemaphoreSlim
, или тот, AsyncLock
который у меня есть как часть моей библиотеки AsyncEx.
Однако, если вам нужен именованный мьютекс, вам придется сделать что-то совсем другое. Что это такое, зависит от того, что именно вы пытаетесь сделать.
Обновление из-за комментариев:
Поскольку вы находитесь в потоке пользовательского интерфейса, нет необходимости вызывать диспетчер. Вам просто нужно SemaphoreSlim
хранить их по одному за раз:
private readonly SemaphoreSlim _mutex = new SemaphoreSlim(1);
//Function that is attached to each pages "LayoutUpdated" call.
private async void AnyPageLayoutUpdated(object sender, object e)
{
await _mutex.WaitAsync();
try
{
LCDDriver.ILI9488.PaintScreen(sender);
}
finally
{
_mutex.Release();
}
}
Комментарии:
1. «ожидание несовместимо с мьютексом» Это… неопределенный. Я имею в виду, что в этом коде много чего может пойти не так, но мне трудно объяснить, как несколько потоков могут одновременно выполнять
try
блок. Согласны ли мы с тем, чтоfinally
блок не будет выполнен до окончанияawait
?2. Поскольку эта функция вызывается в потоке пользовательского интерфейса, я считаю, что мое ожидание избыточно. позвольте мне удалить его и посмотреть, работает ли это. Спасибо за быстрый ответ!
3. Возможно ли, что они выполняются одновременно в одном потоке?
4. @KooKiz:
Mutex
привязан к потоку;await
(в зависимости от контекста) может возобновиться в другом потоке. Однако самое главное, что вся идея мьютекса заключается в том, чтобы предотвратить одновременное выполнение кода до завершения этого блока, тогда как вся идеяawait
состоит в том, чтобы позволить вызывающему потоку выполнять другой код.5. Эй, я так и не поблагодарил тебя должным образом! Семафор по-прежнему был именно тем, что мне было нужно!