Скачиваний:
71
Добавлен:
02.05.2014
Размер:
434.18 Кб
Скачать

Вариант 2: переменная-переключатель

Введем общую переменную right, значением ее будет номер процесса, который имеет право входить в критическую секцию. Реализация "скобок критической секции" для двух процессов с номерами 0 и будет следующей:

1

2

3

4

5

6

7

8

static int right = 0;

void csBegin ( int proc ) {

while ( right != proc );

}

void csEnd( int proc ) {

if ( proc == 0) right = 1;

else right = 0;

}

Процесс, вызвавший функцию csBegin, зацикливается до тех пор, пока не получит права на вход. Разрешение входа производится другим процессом при выходе его из своей критической секции.

Данный алгоритм обеспечивает разделение процессов 0 и 1. Два процесса могут одновременно войти в функцию csBegin, но при этом они только читают переменную right. Одновременное вхождение двух процессов в функцию csEnd невозможно. При обобщении алгоритма на большее число процессов первый процесс переключает право на второй, второй – на третий и т.д., последний – на первый. Если процессы используют разные группы разделяемых данных, то каждая группа может быть защищена своим переключателем, таким образом, не запрещается одновременный доступ к разным разделяемым данным. Это делает политику более либеральной, но при наличии двух и более групп разделяемых данных возможно возникновение тупика, так как группа разделяемых данных – тот же монопольный ресурс. Для предотвращения тупика возможно введение иерархии ресурсов, как было описано в главе 5.

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

Вариант 3: неальтернативные переключатели.

Введем для каждого процесса свою переменную, отражающую его нахождение в критической секции. Эти переменные сведены у нас в массив inside. Элемент массива inside[i] имеет значение 1, если i-й процесс находится в критической секции, и 0 – в противном случае.

Для примеров этого варианта введем функцию, определяющую номер процесса-конкурента:

int other (int proc ) {

if ( proc == 0 ) return 1;

else return 0;

}

Первое решение в этом варианте:

1

2

3

4

5

6

7

8

9

10

static char inside[2] = { 0,0 };

void csBegin ( int proc ) {

int competitor; /* конкурент */

competitor = other ( proc );

while ( inside[competitor] );

inside[proc] = 1;

}

void csEnd (int proc ) {

inside[proc] = 0;

}

Здесь и во всех последующих решениях параметр proc функций csBegin и csEnd – номер процесса, желающего войти в свою критическую секцию или выйти из нее.

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

Решение, однако, не гарантирует взаимного исключения. Возможен случай, когда два процесса одновременно выполнят каждый строку 5 своего кода и, следовательно, войдут в свои критические секции одновременно.

В следующем решении мы меняем местами установку своего признака входа и проверку признака конкурента:

1

2

3

4

5

6

7

8

9

10

static char inside[2] = { 0,0 };

void csBegin ( int proc ) {

int competitor;

competitor = other ( proc );

inside[proc] = 1;

while ( inside[competitor] );

}

void csEnd (int proc ) {

inside[proc] = 0;

}

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

Новое решение:

1

2

3

4

5

6

7

8

9

10

11

12

static char inside[2] = { 0,0 };

void csBegin ( int proc ) {

int competitor;

competitor = other ( proc );

do {

inside[proc] = 1;

if ( inside[competitor] ) inside[proc] = 0;

} while ( ! inside[proc] );

}

void csEnd (int proc ) {

inside[proc] = 0;

}

Процесс устанавливает свой признак вхождения (строка 6). Но если он обнаруживает, что признак вхождения конкурента тоже установлен (строка 7), то он свой признак сбрасывает. Эти действия будут повторяться до тех пор, пока наш процесс не сохранит свой признак взведенным (строка 8), а это возможно только в том случае, если признак конкурента сброшен.

Это решение не может быть принято вот по какой причине. Возможно такое соотношение скоростей процессов, при котором они будут одновременно выполнять строку 7, и одновременно сбрасывать свои признаки. Такая "чрезмерная уступчивость" процессов приведет к бесконечному откладыванию решения о входе в критическую секцию.

Соседние файлы в папке Системное программирование и операционные системы