Взаимное исключение с помощью инструкции TestAndSet()

Книга «Принципы операционной системы» Зильбершатца, Галвина и Ганя содержит следующее определение инструкции 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);

Теперь, как достигается взаимное исключение, если нет условия для установки target в значение TRUE?

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

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

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

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

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


person Community    schedule 20.07.2009    source источник


Ответы (8)


Вот способ интуитивного понимания атомарного TestAndSet.

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

  1. Блокировка удерживается (*цель ИСТИНА): вернуть ИСТИНА и *цель остается ИСТИНА
  2. Блокировка НЕ ​​удерживается: вернуть FALSE, а *target установить в TRUE

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

person Hongbin Liu    schedule 24.05.2010
comment
Не могли бы вы также объяснить, почему он не удовлетворяет условию ограниченного буфера ?? - person nj-ath; 12.09.2014
comment
@ nj-ath, нет точной гарантии, что процесс, ожидающий блокировки, получит блокировку через определенное фиксированное время. - person Diwakar Moturu; 30.05.2018
comment
@nj-ath, ›Если есть несколько процессов, пытающихся попасть в свои критические секции, нет гарантии, в каком порядке они войдут, и любому процессу может не повезти ждать целую вечность, пока они не получат свою очередь в критической раздел. (Поскольку нет никаких гарантий в отношении относительных скоростей процессов, очень быстрый процесс теоретически может снять блокировку, пройти через оставшуюся часть и повторно заблокировать блокировку до того, как более медленный процесс получит шанс.) - person Diwakar Moturu; 30.05.2018

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

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

Я думаю, что ОП неправильно истолковал это как:

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

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

person Harry Johnston    schedule 15.08.2012

А, у меня тоже был такой вопрос. Позвольте мне поделиться своим пониманием.

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

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

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

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

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

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

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

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

Другие P придут и увидят, что цель ИСТИНА, и при вызове TestAndSet(boolean_ref lock) она всегда будет возвращать ИСТИНА, пока P1 не установит цель на ложь.

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

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

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

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

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

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

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

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

person prime    schedule 04.02.2016

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

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

Уточнение: я уверен только в том, что функция выполняется, когда цель ложна, потому что где-то это должна быть блокирующая операция сравнения. Есть два типа TestAndSet — один, который возвращает только тогда, когда цель установлена ​​в True (блокировка), и другой, который может возвращать False, т.е. возвращаться немедленно (тот, который разрешает опрос другим потоком). Я предполагаю, что тот, который вы цитируете, блокирует, потому что он, кажется, возвращается сразу после начала выполнения, что означает, что оператор «IF» выполняется механизмом более низкого уровня, например. ядра ЦП или ОС.

person Roee Adler    schedule 20.07.2009
comment
Я не сталкивался с тем, что TestAndSet() выполняется только тогда, когда цель ложна. Я проверил оба учебника и Википедию. Тем не менее, это имеет смысл, я посмотрю на это. - person ; 20.07.2009
comment
В показанном примере нет блокировки, цикл while(TestAndSet()) просто вращается до тех пор, пока условие не изменится. Хотя это расточительно использует ЦП, потоки на самом деле не должны блокироваться, ожидая, что что-то произойдет. Посмотрите spinlock в Википедии для получения дополнительной информации. - person Harry Johnston; 15.08.2012

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

HdwareData lock = new HdwareData(false);
person Ahmed Salwh    schedule 15.03.2010

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

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

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

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

person sbetageri    schedule 05.12.2015

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

(1) вы правильно заявили, что target безоговорочно установлено в TRUE, и поняли (ошибочно), что это проблема.

(2) Чтобы решить проблему в (1) (которой не существует), вы предложили протестировать target, прежде чем устанавливать для него значение TRUE.

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

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

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

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

person Humberto Fioravante Ferro    schedule 13.04.2017

Рассмотрим следующую выделенную часть вашего вопроса:

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

P1 (или любой другой процесс), независимо от того, является ли блокировка True или False, не устанавливает значение блокировки в False.

  • Если блокировка имеет значение False, она входит в критическую секцию и устанавливает значение True, тем самым захватывая блокировку.

  • Если значение блокировки равно True, он ничего не делает (устанавливает значение True, тем самым не изменяя его) и ждет, пока значение блокировки не станет False (что происходит, когда процесс, имеющий блокировку, завершает выполнение своего критического раздела).

person Diwakar Moturu    schedule 30.05.2018