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

2. Контекст потока

В общем случае содержимое памяти, к которой поток имеет доступ во время своего исполнения, называется контекстом потока. Определим, каким ограничениям на доступ к памяти должны удовлетворять функции, чтобы их можно было безопасно вызывать в параллельных потоках. Для этого рассмотрим следующую функцию:
< int f (int n)
{
  if (n > 0)
  --n;
  if (n < 0)
  ++n;
  return п;
}

Сколько бы раз эта функция не вызывалась параллельно работающими потоками, она будет корректно изменять значение переменной n, т. к. эта переменная является локальной в функции f. То есть для каждого нового вызова функции f будет создан новый локальный экземпляр переменной n. Такая функция f называется безопасной для потоков. Теперь введем глобальную переменную n и изменим нашу функцию следующим образом:

int n;
void g()
{
  if (n > 0)
  --n;
  if (n < 0)
  ++n;
}

В этом случае параллельный вызов функции g несколькими потоками может дать некорректное изменение значения переменной n, т. к. значение этой переменной будет изменяться одновременно несколькими функциями g. В этом случае функция g не является безопасной для потоков.
Та же проблема встречается и в случае, когда функция использует статические переменные. Для разбора этого случая рассмотрим функцию:

int count(}
{
  static int n = 0;
  ++n;
  return n;
}

которая возвращает количество своих вызовов. Если эта функция будет вызвана несколькими параллельно исполняемыми потоками, то нельзя точно определить значение переменной n, которое вернет эта функция, т. к. это значение изменяется всеми потоками параллельно.

В общем случае функция называется повторно входимой или реентерабельной (reentrant или reenterable), если она удовлетворяет следующим требованиям:

  • не использует глобальные переменные, значения которых изменяются параллельно исполняемыми потоками;
  • не использует статические переменные, определенные внутри функции;
  • не возвращает указатель на статические данные, определенные внутри функции.

В системном программировании часто также рассматриваются программы в кодах микропроцессора, выполнение которых может прерываться и возобновляться в любой момент времени. Причем одна и та же программа может запускаться прежде, чем завершилось исполнение предыдущего экземпляра этой программы. В этом случае также необходимо, чтобы программный код допускал корректное параллельное выполнение нескольких экземпляров программы. Это условие обеспечивается в том случае, если программа не изменяет свой код во время исполнения. Здесь под кодом подразумеваются как команды, так и данные, принадлежащие программе. Программа в кодах микропроцессора, которая не изменяет свой код, также называется реентерабельной.
В дополнение к реентерабельным функциям определяют также функции, безопасные для вызова параллельно исполняемыми потоками. Функция называется безопасной для потоков, если она обеспечивает блокировку доступа к ресурсам, которые она использует. Как обеспечить блокирование доступа к ресурсам, рассматривается на следующих занятиях, посвященных синхронизации потоков. Сейчас же только скажем, что в этом случае решается задача взаимного исключения доступа к разделяемым ресурсам, используя примитивы синхронизации.
Очевидно, что если функция не является реентерабельной, то она также не является и безопасной для потоков, т. к. в этом случае несколько потоков разделяют общую память, не блокируя доступ к ней. А память, как уже говорилось, также является системным ресурсом.

 

 


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