System ::Threading :: Mutex, вызывается из несинхронизированного блока кода. Неожиданная взаимоблокировка

#multithreading #c -cli #ipc #mutex #deadlock

#многопоточность #c -cli #ipc #мьютекс #взаимоблокировка

Вопрос:

В попытке избавить мой графический интерфейс от условий гонки и взаимоблокировок у меня есть следующая функция, которую я вызываю из c’torи всякий раз, когда мне нужна служба, которая разделяет мое имя mutex , чтобы предоставить его ввод:

 void EnvCapt::FireServiceAndOrHold() {
    try {
        mutTimerSyncEx->ReleaseMutex();
        Thread::Sleep(100); //Time enough for the service to complete.
        if (!mutTimerSyncEx->WaitOne(3 * int_ms)) {//int_ms = the polling period
            //Must've been doubly locked or worse.
            mutTimerSyncEx->ReleaseMutex();
            FireServiceAndOrHold();
        }
    } catch (Exception ^ ex) {
        //Released unheld mutex. Retake control.
        mutTimerSyncEx->WaitOne();
        FireServiceAndOrHold();
    }
}
  

Это работает относительно хорошо, но я вызываю это, прежде чем разрешить службе, теперь я готов принять ввод, поэтому он никогда не пытается ждать, пока я выпущу для него мьютекс. Прежде чем я попытаюсь изменить порядок вещей, я хотел бы знать, что происходит не так с вышеупомянутой функцией. Ошибка, которую я получаю,:

Метод синхронизации объекта был вызван из несинхронизированного блока кода.

Поскольку вызов release для a mutex , который не был WaitOne ‘d, приведет к сбою, я поймаю это, зная, что я могу взять на себя ответственность за это и продолжить. Но я ошибаюсь. Он навсегда зависает в WaitOne() инструкции. Я знаю, что делает другой процесс все это время, потому что он заблокирован в моем втором окне отладчика. Это не касается мьютекса.

Обновить

Я попытался изменить порядок, который я сначала предложил, это показалось хорошим, но теперь я обнаружил, что мьютекс является только глобальным, несмотря на наличие глобального name .

  • Он является общим, потому что, когда мой графический интерфейс c’tor’s firstInstance имеет значение false, поэтому я пытаюсь взять его под контроль.

  • Он не является общим, потому что, когда графический интерфейс вызывает WaitOne() его, графический интерфейс блокируется на неопределенный срок. В то время как служба танцует прямо через свой вызов WaitOne() , не заботясь ни о чем в мире.

Комментарии:

1. почему вы используете примитивы синхронизации и повторяете предположение («должно быть, была двойная блокировка …» и «зная, что я могу взять на себя ответственность за это и продолжить» -> это так не работает. Вы НИКОГДА не сможете узнать, что «вы можете стать владельцем», если вы не держите мьютекс заблокированным . Остальное — это просто «улучшенное» условие гонки (возможно, мьютекс был заблокирован, когда вы получили исключение). Кроме того, исключения предназначены для исключительных ситуаций.

2. Если я выпускаю общий именованный мьютекс, и он выдает, это может означать только то, что он не заблокирован. Поэтому я могу взять на себя ответственность. В некоторых ситуациях исключения происходят постоянно и должны быть устранены, если это единственный способ решить проблему. Пожалуйста, это относится к .NET, а не к C -CLI, перевод минимален, когда мы имеем дело с такими высокоуровневыми концепциями, как мьютекс и синхронизация. Или, что угодно, просто верните моему коду его цвет!

3. нет. Вы только что определили условие гонки. Возможно, он был заблокирован в то же время. Кроме того, нет абсолютно никакой необходимости перехватывать исключение при освобождении мьютекса, который вы не удерживаете, потому что вы всегда можете узнать, удерживали ли вы его уже. Это то, что я имел в виду, говоря «исключения для исключительных ситуаций».

4. Нет, не заблокирован ничем, чего я не вижу. У меня есть отладчик для потоков обоих процессов, практически в каждой строке есть точки останова.

5. Условие гонки, которое описывает sehe, — это когда вы проверили статус блокировки, а затем попытались ее принять. Между этими двумя действиями другой поток, возможно, уже предпринял его. То, что вы знаете, что другой поток в данный момент этого не делал, не означает, что это невозможно при дальнейших исполнениях.

Ответ №1:

У меня просто возникла идея, что может быть не так у вас там:

Подсказка: вы не можете освободить мьютекс от имени другого процесса! Другой процесс должен будет освободить мьютекс, если он его удерживает:

 Process 1:                           Process 2:
============                         =============

    WaitOne (locks the mutex)

    // do work                       WaitOne (awaits the mutex)

    // do more work

    // done
    ReleaseMutex         ------>     WaitOne returns from the wait _with 
                                             the mutex locked_
  

Комментарии:

1. Я могу выпустить общий мьютекс с глобальным именем от имени другого процесса, иначе какой смысл делиться? Они не будут синхронизироваться. Хм, я вижу, где я, возможно, нарушил его. Возможно, до сих пор все они снимали свои собственные блокировки, но это не похоже на совместное использование, если у каждого есть отдельные блокировки. Не думаю, что у меня есть время проверить это сегодня вечером. Можете ли вы сослаться на некоторые доказательства того, что вы описываете?

2. @John: какой смысл удерживать блокировку, если другой процесс может освободить ее от вашего имени ? Пожалуйста, сначала ознакомьтесь с примитивами синхронизации. редактировать : я думаю, вы хотите назвать события

3. Что касается доказательств: ваш вопрос, похоже, несет его. Редактировать Теперь я вижу вашу правку. Успокойтесь, удачи в поиске ошибок завтра!

4. Вы определенно не можете освободить ресурсы, которые вам не принадлежат. Какой смысл что-то блокировать, если кто-то другой может просто снять вашу блокировку в середине того, что вы делали?

5. Черт возьми, я просто добавляю новые условия гонки со всеми моими точками останова. Так много для моей системы реального времени. Спасибо, ребята. Извините, если я причинил какое-либо оскорбление, на этой неделе было несколько поздних ночей, и я продрог до костей. Приятно, вопрос в качестве доказательства 1