Page 102 - 6571
P. 102
Але в такому випадку знову виникають конфлікти звернення
до пам’яті, причому таке рішення є досить неефективним,
оскільки суму елементів arrive[i] тепер постійно обчислює
кожен очікуючий своєї черги процес Worker.
Обидві проблеми (конфлікти звернення до пам’яті і
обнулення масиву) можна вирішити, використавши додатковий
набір спільних значень і додатковий процес Coordinator. Нехай
кожен процес Worker замість того, щоб підсумувати елементи
масиву arrive, очікує, доки єдине логічне значення не стане
«істина». Нехай continue[1: n] – додатковий масив цілих
чисел з нульовими початковими значеннями. Після того як
процес Worker[i] присвоїть значення 1 елементу масиву
arrive[i], він переводиться в режим очікування до того часу,
доки значенням змінної continue[i] не стане 1.
arrive[i] = 1;
<await (continue[i] == 1);>
Процес Coordinator очікує, поки всі елементи масиву
arrive не стануть рівні 1, а потім присвоює значення 1 всім
елементам масиву continue.
for [i = 1 to n] < await (arrive[i] == 1);>
for [i = 1 to n] continue[i] = 1;
Оператори await можна реалізувати у вигляді циклів while,
оскільки кожен із них посилається лише на одну спільну змінну.
У процесі Coordinator для очікування процедури присвоєння
значень всім елементам arrive можна використати оператор
for. Оскільки для продовження роботи процесів Worker повинні
бути встановлені значення для усіх елементів масиву arrive, то
процес Coordinator може перевіряти їх у довільному порядку.
Конфліктів звернення до пам’яті тепер не буде, оскільки процеси
очікують зміни різних змінних, кожна з яких може зберігатися у
своєму рядку кеш-пам’яті.
Змінні arrive та continue в представлених програмах є
прикладами так званого прапорця. Його встановлює (піднімає)
один процес, щоб повідомити іншого про виконання умови
синхронізації. Доповнимо програми кодом, який скидає прапорці
(присвоюючи їм значення 0) для підготовки їх до наступної
ітерації. При цьому використовуються два основних правила
101