Семафоры. Блокировки (Locks).
Семафором называется объект ядра, который позволяет только одному процессу или одному потоку процесса обратиться к критической секции – блоку кодов, осуществляющему доступ к объекту. Серверы баз данных используют их для защиты разделяемых данных. Классический семафор был создан Dijkstra, который описал его в виде объекта, который обеспечивает выполнение двух операций Р и V. Первая литера является сокращением голландского слова Proberen, что означает тестирование, вторая – обозначает глагол Verhogen, что означает приращивать (increment). Первая операция дает доступ к ресурсу, вторая – запрещает доступ и увеличивает счетчик объектов, его ожидающих. Различают два основных использования семафоров: защита критической секции и обеспечение совместного доступа к ресурсу.
В качестве примера может служить критическая секция в виде функции, осуществляющей доступ к таблице базы данных.. Другим примером может служить реализация списка операционной системы, который называется process control blocks (PCBs). Это список указателей на активные процессы. В каждый конкретный момент времени только один поток ядра системы может изменять этот список, иначе будет нарушена семантика его использования.
Семафор может быть использован также для управления перемещением данных (data flow) между n производителями и m потребителями. Существует много систем, имеющих архитектуру типа data flow. В них выход одного блока функциональной схемы целиком поступает на вход другого блока. Когда потребители хотят получить данные, они выполняют операцию типа Р. Когда производители создают данные, они выполняют операцию типа V.
Традиционно семафоры создавались как глобальные структуры, совместно с глобальными API-функциями, реализующими операции Р и V. Теперь семафоры реализуются в виде класса объектов. Обычно абстрактный класс Семафор определяет чисто виртуальные функции типа Р и V. От него производятся классы, реализующие два указанных типа семафоров: защита критической секции и обеспечение совместного доступа к ресурсу. В смысле видимости оба типа семафоров могут быть объявлены либо глобально во всей операционной системе, либо глобально в пространстве процесса. Первые видны всем процессам системы и, следовательно, могут ими управлять. Вторые действуют только в пространстве одного процесса и, следовательно, могут управлять его потоками.
Сам семафор ничего не знает о том, что он защищает. Ему обычно передается ссылка на объект класса, который хочет использовать критическую секцию, и он либо дает доступ к объекту, либо подвешивает (suspends) объект до тех пор, пока доступ не станет возможным. Важно отметить, что при реализации семафоров и других объектов ядра используют специальные атомарные команды (atomic steps), которые не прерываются системой.
Блокировки (Locks)
Блокировки – это семафоры, которые приспособлены для двух операций транзакции (commit и abort). Они используются для обеспечения последовательного доступа конкурирующих потоков или процессов к критическим секциям. Обычно в базах данных блокируется некоторое множество данных (range of items), так как блокировка одного элемента более накладна. Представьте такой запрос:
Select * from Customer where country = Russia and city = "Moscow";
Чтобы защитить данные от рассмотренных выше неприятностей, надо заблокировать все строки таблицы, которые удовлетворяют указанному критерию поиска. Такой способ защиты, оказывается, обладает побочным эффектом. Он может породить запись-призрак (phantom). Допустим, что в это же время другой поток процесса добавляет в ту же таблицу Customer (Клиент) новую запись и ее поля удовлетворяют тому же критерию (клиент из Москвы). Она, конечно же, будет добавлена в таблицу, но для первого потока она является фантомом (не существует).