Мой Мьютекс не работает

#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. Эй, я так и не поблагодарил тебя должным образом! Семафор по-прежнему был именно тем, что мне было нужно!