Форумы Серверы Суспільство
Игры Серверы VBIOS General Soft & Hard Увлечения А поговорить... Культура Полезная информация Межигір'я Чат

Пользователь Сообщение: Программирование для падонков: Синхронизация процессов        (Тема#10603)
Boo'ka 
подполковник
Boo
Возраст: 36
: Otherwhere
С нами с 29.11.05
Посты: 2253
15.09.06 15:26 Ukraine #203767
Программирование для падонков: Синхронизация процессов


September 10, 2003

Андрей Платов

Рассмотрим простую жизненную ситуацию, а именно: падонок захотел пассать. Реализация этого действа довольно проста: найти толчок (ну либо другое адекватное место) и абассаца. Далее мы упростим задачу до пользования общественным туалетом общего назаначения (как абассатся в любом подходящем месте рассматривается в неизданной главе интерфейсы и, более полно, в неизданной главе Adapter Pattern из "Продвинутого ООП для падонка").

Соответственно мы имеем следующую модель (упрощённо):

1. класс падонок с методом "облегчится" (реализация может быть как по-большому так и по-маленькому, что в данном случае не важно).
2. класс толчок с методом "принять" (кстати с этим классом мы встречаемся во многих местах - наиболее активно он участвует в главе Visitor Pattern из того-же "Продвинутого ООП для падонка")

На себя мы берём роль создателя и наша задача запрограммировать падонков (да и толчки) так, чтоб они не обламывались... Здесь и далее Java.

public class Padonok extends ... implements Reliefer, ... {
...
public void relief() {
//найти место для облегчения
ReliefPlace place = findPlaceToRelief();
place.accept(this);
}
...
}

public class OO implements ReliefPlace {
...
public void accept(Reliefer visitor) {
// здесь зависит от производителя толчка
// например продвинутый биоталчок может
// включить приятную музыку
}
...
}

И было бы всё здорово, но что же произойдёт если вдруг два падонка захотят облегчится в один и тот же толчок, причём один решит пассать туда в тот момент, когда на очке как гордый орёл восседает его колега по идеологии? Варианты могут быть самые разные, ясно лишь, что кто-то обломается. Что же делать? Здесь всё зависит от таланта программиста. Немного отходя от темы покажу что делает программист-долбоёб (ПД).

Первое, что делает ПД это "умного падонка", а именно добавляет в метод "облегчится" код подобный "если на толчке сидит другой падонок, то подождать 30 секунд и повторить". После того как программа ПД абассыт маленького мальчика, который еще не является падонком, он начинает обучать падонка дальше. Например, начинает вешать возле толчка табличку "занято", соответственно переписав метод "облегчиться" на поиск и вывешивание таблички, проверку ее наличия и т.д...

После того, как программа ПД абассыт уборщицу, которая зашла в толчок не для того чтоб облегчится, а просто убраться и не повесила табличку, ПД начинает вывешивать и проверять долбаные таблички везде где ни попадя или начнёт делать "умный толчок", который сам начнёт вывешивать табличку при входе в него кого-бы то ни было...

После того как его падонок навсегда застрянет перед толчком поскольку кто-то забыл снять табличку или объект класса "отморозок" абассыт "умного падонка" (поскольку класс "отморозок" был реализован другим программистом, который забыл про таблички, придуманые ПД, да и ваще он на них клал) ПД основательно задумается и, наконец, начнёт закрывать двери.

Вот теперь подробнее о дверях. Двери бывают разные и ПД может начать придумывать свои двери, например такие:

interface Door {
boolean isOpen();
void open();
void close();
}

И, соответственно код:

...
while(!door.isOpen())
... //как-то подождать
door.close();
try {
... // абассаца
} finally {
door.open();
}
...


Такие двери мало чем отличаются от вышеупомянутых табличек со всеми сопутствующими проблемами: а именно везде должен присутствовать код, проверяющий, открывающий и закрывающий их; минимальная ошибка и кого-нить абассут, или кто-нибудь абассытся по причине отсутствия открытого толчка.

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

Каждый падонок действует сам по себе и его логика выполняется в собственном контексте исполнения для Java внутри виртуальной машины такой контекст исполнения - это поток (thread). Теперь посмотрим, что может случится с этой дверью если через него ломанётся два подонка почти одновременно:


Падонок 1 (поток 1)

Падонок 2 (поток 2)


...
while(!door.isOpen()) //дверь открыта
...
...
door.close(); //закрыть

try {
... //абассаца
} finally {
door.open();
}
...

...
...
while(!door.isOpen()) //дверь открыта
... //падонок 1 еще не закрылся
...
door.close();//закрыть закрытую
//падонком 1 дверь еще раз
try {
... //абассать падонка 1
} finally {
door.open();
}
...

В любом случае, даже если дверь не сломается, падонок 1 будет абоссан и пред нами стоит следующая задача: сделать так, чтоб некоторая последовательность операций над каким-то объектом могла быть исполнена не более чем одним потоком одновременно.

В виртуальной машине для этого реализованы т.н. мониторы. О мониторах обычному программисту необходимо знать не больше чем обычному человеку о солнце. А именно то, что по утрам оно встаёт, по вечерам заходит, а еще то, что оно светит, и так будет всегда.

Так вот, свой монитор есть у каждого объекта (и как бы вы не выёбывались, он всё равно есть, и только один для каждого объекта в виртуальной машине). Кроме того, любой поток может захватить и освободить монитор, но только в том случае, если монитор не захвачен другим потоком. Если поток 1 пытается захватить монитор захваченный потоком 2, то выполнение потока 1 приостанавливается до тех пор пока поток 2 не освободит монитор. Вот по большому счёту и всё, а теперь о том накой это нужно.

Монитор объекта и есть та дверь, которая не пустит более одного потока (падонка) пассать в данный объект (толчок). Для этого поток (падонок) должен захватить монитор на входе в талчок и освободить при выходе. В языке Java для захвата/освобождения монитора есть ключевое слово synchronized:

synchronized(oo) {// захватить монитор объекта oo
... // пассать в талчок
} // монитор освобождается виртуальной
// машиной при выходе из блока

Монитор освобождается виртуальной машиной при выходе из synchronized блока причём не важно как вы из этого блока вышли (нормально, с исключительной ситуацией, или вышли из функции командой return) - монитор освободится в любом случае и это задача виртуальной машины. Кроме того код внутри блока не будет исполнен двумя и более потоками одновременно (это следует из свойств монитора описанных выше) при условии что "oo" - один и тот же объект.

Существует и другая форма synchronized блока. Ключевое слово synchronized можно указать в спецификации метода, в таком случае монитор объекта this будет захвачен потоком, вызвавшим данный метод, и, соответственно освобождён при выходе из метода. Т.е.

synchronized void x() {
...
}

эквивалентно

void x() {
synchronized(this) {
...
}
}


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

// облегчится
public void relief() {
//найти место для облегчения
ReliefPlace place = findPlaceToRelief();
synchronized(place) {
... //облегчится
}
}
...

Обратите внимание: synchronized(place) - мы захватываем монитор того отхожего места, которое собираемся посетить, чтоб другой падонок не мог сделать то же самое пока мы этот монитор не освободили. Я десятки раз видел как ПД хуярят synchronized в спецификаторы метода relief, наивно полагая что это им поможет. Да это им в данном случае ваще нихуя не даст.

Врод бы задача решена, но чтобы уж дойти до конца, необходимо отметить вот еще что: в данной реализации захват/освобождение туалетного монитора реализован в классах-пользователях толчка. Таких как класс "падонок" и др. В далнейшем может появится множество таких классов, принадлежащих разным иерархиям и во всех них придётся не забывать о необходимости захвата монитора. Это не есть хорошо. Гораздо правильние было бы захватить монитор в методе самого толчка - тогда о захвате/освобождении монитора позаботится сам толчок. Пример:

public class OO implements ReliefPlace {
...
public synchronized void accept(Reliefer visitor) {
visitor.visit(this); //говорим посетителю чтоб ссал сюда
}
...
}

public class Padonok extends ... implements Reliefer, ... {
...
public void visit(ReliefPlace oo) {
//облегчится в толчок oo
//толчковый монитор уже захвачен
//при входе в метод accept толчка
}
...
}

Ну и в оконцовке еще замечу, что в большинстве операционных систем, программных продуктах, литературе и т.д. штука, подобная монитору Java называется mutex - сокращение от Mutual Exclusion (Взаимное Исключение), и, в свою очередь является примером семафора с областью значений 0..1.
Tester_1 
генералиссимус
Tester_1
Возраст: 43
: Kovel,Ukraine
С нами с 10.11.03
Посты: 13369
15.09.06 17:30 [Re: Boo'ka] Ukraine #203768
Такого про мьютексы я еще не читал!
Nameless 
Maximus - Lite Edition
Nameless
: 404
С нами с 02.11.05
Посты: 21233
19.09.06 14:40 [Re: Tester_1] Ukraine #203769
классно объяснил, зачет
Icon Legend Права Настройки темы
Распечатать тему


1528 Просмотры
Реклама
182 сейчас в онлайне
12 пользователей (Hac9lJlbHuKe, artyom-310608, Серхио, Eger, powerp, Lam0, 6APMALEU, Евлампий Петрович, Pandemonium_1, Din0saur, CJlOH, JazzTwist) и 1 скрытых, а также 169 гостей сейчас онлайн.
     
VBIOS Version 3.0 FINAL | ©1999-2020
Execution time: 0.051 seconds.   Total Queries: 28   Zlib сжатие вкл.
All times are (GMT+2.0). Current time is 16:41
Top