К Т П           План занятия                                                              1                                           Страницы  | 1 | | 2 | | 3 | | 4 | | 5 | | 6 | | 7 | | 8 | | 9 |

5. Аппаратная реализация синхронизации

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

Инструкция "проверить и установить"

В наборе инструкций процессора Motorola 68000 существует инструкция tas (test and set), которая имеет следующую реализацию:
int tas{int& target)
{
  int temp;
  temp = target;
  target = 1;
  return temp;
}

Выполняется она непрерывным образом, т. е. выполнение этой инструкции не прерывается. Используя эту инструкцию, можно реализовать взаимоисключающий доступ параллельных потоков к критической секции по следующему алгоритму:
int lock = 0; // переменная, которая запирает вход в критическую секцию
void thread()
{
while(true)
  {
   while(tas(lock) ) ; // ждать, пока замок закрыт
   critical_section() ; // критическая секция
   lock = 0; // открыть замок
   non critical section(); // остальной код
  }
}

Покажем, что этот алгоритм удовлетворяет требованию безопасности. Для этого предположим противное, т. е. что критические секции выполняются одновременно в двух разных потоках. Это может произойти только в том случае, если инструкции tas(lock), исполняемые в разных потоках, прервали друг друга. Но это невозможно, т. к. инструкция tas выполняется непрерывным образом. Следовательно, наше предположение неверно и в критической секции может находиться только один из потоков.

Теперь покажем, что этот алгоритм удовлетворяет требованию поступательности. Для этого предположим противное, т. е. что все потоки одновременно заблокированы на выполнении СВОИХ ЦИКЛОВ while (tas (lock)). Но это возможно только в том случае, если начальное значение переменной lock было равно 1, что противоречит тексту программы. Следовательно, наше предположение неверно и требование поступательности выполняется.

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

Инструкция "обменять содержимое переменных"

В наборе инструкций процессоров семейства Intel х86 существует инструкция xchg (exchange), которая имеет следующую реализацию:
void xchg(register int r, int x)
{
  int temp;
  temp = r; r = x; x = temp;
}

и выполняется непрерывным образом, т. е. выполнение этой инструкции не прерывается. Используя эту инструкцию, можно реализовать взаимоисключающий доступ параллельных потоков к критической секции по следующему алгоритму:
int lock = 0; // переменная, которая запирает вход в критическую секцию
void thread()
{
  while(true)
   {
register int key; // ключ к замку
key = 1;
while(key == 1) // ждать, пока замок закрыт
xchg(key, lock);
critical_section(); // критическая секция
lock = 0; // открыть замок
non_critical_section(); // остальной код
   }
}

По аналогии с алгоритмом, использующим инструкцию tas, можно показать, что приведенный алгоритм также удовлетворяет двум первым требованиям, выдвигаемым к решению задачи взаимного исключения.
Для того чтобы терминологию, относящуюся к аппаратной синхронизации потоков, сделать независимой от типов команд, которые используются в процессорах для этих целей, ввели такое понятие, как спин блокировка (spinlock) или активное ожидание. Спин блокировкой называется цикл while с непрерываемой командой процессора, который ждет разрешения на вход в критическую секцию.

В заключение этого раздела сделаем два важных замечания. Во-первых, аппаратные алгоритмы синхронизации могут использоваться любым количеством параллельных потоков. Во-вторых, как программные, так аппаратные алгоритмы синхронизации имеют один существенный недостаток: впустую тратится процессорное время в циклах while, ждущих разрешения на вход в критическую секцию. Поэтому все эти алгоритмы получили общее название алгоритмы, занимающиеся ожиданием (busy waiting algorithms), или алгоритмы активного ожидания.



Предыдущая        В начало страницы       Следующая
5