Подтвердить что ты не робот

Взаимное исключение с использованием команды TestAndSet()

Принципы работы операционной системы Silberschatz, Galvin и Gagne содержат следующее определение для команды TestAndSet() в главе о синхронизации:

boolean TestAndSet(boolean *target) {
    boolean rv = *target;
    *target = TRUE;
    return rv;
}

Реализация взаимного исключения с использованием вышеуказанной инструкции также предоставляется следующим образом:

do {
    while(TestAndSetLock(&lock))
        ; // do nothing
        // critical section
    lock = FALSE;
        // remainder section
} while(TRUE);

Теперь, как достигается взаимное исключение, если нет условия для установки цели на ИСТИНА?

Рассмотрим следующую ситуацию: процесс P0 устанавливает блокировку разделяемой переменной в TRUE и входит в ее критический раздел. Другой процесс P1 вызывает TestAndSet() в цикле while выше, он возвращает TRUE (поскольку P0 имеет блокировку), но безостановочно устанавливает блокировку в FALSE. Второй раз, когда TestAndSet() вызывается в цикле while, он возвращает FALSE, а P1 переходит в критический раздел, хотя P0 находится в критическом разделе. Затем нарушается взаимное исключение.

Я несколько раз искал и наткнулся на статью Митхуна Ачарьи и Роберта Фундерика (из отдела CS Университета Северной Каролины), которая содержит следующее альтернативное определение TestAndSet():

   boolean Test-and-Set(boolean target)
    begin
        if(target == false):
            target = true;
        return target;
    end

Это имеет для меня гораздо больше смысла, я включил его для сравнения, а также потому, что в статье перечисляется книга Сильбершаца как одна из его ссылок.

Я просто не понимаю, как определение, которое я нашел в своем учебнике (тот, который я представил вначале), можно использовать для обеспечения взаимного исключения, может ли кто-нибудь помочь?

4b9b3361

Ответ 1

Вот способ интуитивно думать об атомном TestAndSet.

Нить использует его перед входом в критическую область. Только два случая:

  • Блокировка удерживается (* target TRUE): возвращает TRUE и * target остается TRUE
  • Блокировка НЕ ​​удерживается: return FALSE и * target установлено значение TRUE

Таким образом, любой другой поток находится в критической области, поэтому * target (TRUE) отражает то, что должно быть значением; или "Я" сейчас вхожу в эту критическую область, поэтому установите * target в значение TRUE.

Ответ 2

Функция TestAndSet, которую вы изначально цитируете, выполняется только тогда, когда цель ложна. То есть поток блокируется до тех пор, пока цель не станет ложной. У меня нет этого учебника, но я уверен, что он упоминается где-то в тексте.

Обратите внимание, что TestAndSet - это "атомная" функция, которая должна быть реализована на самых низких уровнях ОС (или даже в наборе инструкций CPU). Если он реализован в пользовательском приложении, между тестом и множеством может возникнуть контекстный переключатель, вызывающий повреждение.

Уточнение: я уверен только в том, что функция выполняется, когда цель ложна, потому что где-то это должна быть операция сравнения, которая блокирует. Существует два типа TestAndSet - один, который возвращается только тогда, когда для целевого объекта установлено значение "Истина" (блокировка), и тот, который может возвращать False, т.е. Немедленно вернуть (тот, который включит опрос другим потоком). Я предполагаю, что тот, который вы цитируете, блокирует, потому что он, кажется, возвращается сразу после запуска выполнения, что означает, что оператор "IF" выполняется механизмом более низкого уровня, например. ядра процессора или ОС.

Ответ 3

Показанная реализация может быть написана более четко:

while(TestAndSet(&lock))
{
   // spin in this loop until TestAndSet returns false
}
do_critical_section_stuff();
lock = FALSE;
// We've now left the critical section

Я думаю, что OP неправильно интерпретировал его как:

while(TestAndSet(&lock))
{
   lock = FALSE;
}
do_critical_section_stuff();

который не будет работать должным образом по понятным причинам.

Ответ 4

У меня тоже был этот вопрос. Позвольте мне поделиться своим пониманием.

Изначально * target будет FALSE. (что задано). Это правда, что P должен пройти while(TestAndSetLock(&lock)) ; // do nothing чтобы получить блокировку и войти в критический раздел. (получение блокировки - всего лишь гипотетическая вещь, если она может пройти цикл while, тогда она имеет блокировку)

у кого-то есть средство блокировки target ИСТИНА, блокировка может быть выбрана target ЛОЖЬ. поэтому в начале это так,

введите описание изображения здесь

введите описание изображения здесь

P1 (самый первый вызов функции повезет), он видит, что цель FALSE и установить ее в true и RETURN FALSE, что приводит к ее недопущению ожидания цикла while.

введите описание изображения здесь

введите описание изображения здесь

Теперь цель TRUE. Другой факт: TestAndSet (блокировка boolean_ref) возвращает вызываемое значение, И TestAndSet (блокировка boolean_ref) будет ВСЕГДА установить цель в ИСТИНА поэтому кто-то должен установить цель в ЛОЖЬ в другом месте (так что один с блокировкой может установить его в ЛОЖЬ)

Появится другое значение P, и эта цель будет TRUE, и при вызове TestAndSet(boolean_ref lock) она вернет TRUE всегда, пока P1 не установит цель в значение false.

введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь

И я нашел это приятное графическое объяснение от Этот сайт вы можете скачать здесь

Ответ 5

Чтобы использовать метод testAndset, мы начинаем с переменной Lock, для которой установлено значение false:

HdwareData lock = new HdwareData(false);

Ответ 6

Подумайте не линейно. Вы указали три вопроса в определении Silberchatz для реализации функции testAndSet():

(1) вы правильно заявили, что цель установлена ​​на ИСТИНА безоговорочно и реализована (ошибочно), что является проблемой.

(2) Чтобы решить проблему в (1) (которая не существует), вы предложили протестировать целевую аудиторию, прежде чем устанавливать ее в ИСТИНА.

(3) Наконец, вы показали свою озабоченность в связи с тем, что результат также установлен FALSE также безоговорочно блоком, который реализует взаимное исключение (это на самом деле не происходит).

Я попытаюсь прояснить эти проблемы. Первоначально обратите внимание, что первая вещь, которую выполняет функция TestAndSet(), - это копирование значения цели в rv, и только после этого цель устанавливается безоговорочно в TRUE. Теперь catch: если цель была первоначально FALSE, TestAndSet() устанавливает цель в TRUE и возвращает FALSE, поэтому процесс может войти в критический раздел. Если исходное целевое значение было TRUE, оно равно TRUE в любом случае (что не причиняет вреда), а TestAndSet() возвращает TRUE, поэтому процесс не может войти в критическую область. Таким образом, установка цели безоговорочно в TRUE не является проблемой, а проблема (1) оказывается несуществующей.

Относительно проблемы (2), как только будет показано выше, безоговорочно установить целевое значение TRUE безоговорочно, нет необходимости предварительно проверять его значение.

Проблема (3) также не существует, потому что результат на самом деле не установлен безоговорочно FALSE. Я имею в виду, что это так, но только ПОСЛЕСЛОВИЯ критический регион был обработан процессом; т.е. когда взаимное исключение больше не требуется. Этот процесс должен установить цель в ЛОЖЬ, как только он покинет критический раздел (он не должен блокировать другие процессы после выхода из критического раздела). Обязательно освободить блокировку после обработки критического раздела!

Ответ 7

Изучая реализацию взаимного исключения TestAndSet (& lock), можно с уверенностью сказать, что до тех пор, пока TestAndSet возвращает true, процесс (P) не войдет в его критический раздел. Процесс будет продолжать выполняться в состоянии цикла, пока он (условие) не завершится.

Условие будет успешным (TestAndSet вернет true), пока другой процесс имеет блокировку ресурса. Когда другой процесс имеет блокировку ресурса, значение блокировки истинно. Как только другой процесс освободит свой ресурс, установив lock = false, TestAndSet вернет false.

Когда TestAndSet возвращает false, условие для цикла while терпит неудачу и, следовательно, процесс P входит в его критический раздел.

TestAndSet - это атомная операция, то есть она выполняется без перерывов. Это делается для предотвращения условий гонки с блокировкой.