Реентерабельность функций
Функция называется реентерабельной,
если она корректно работает при одновре-
менном ее вызове из нескольких задач и/или
прерываний. Под одновременным вызовом
понимается вызов функции из одной задачи
в тот момент, когда та уже вызвана из другой
задачи, но еще не выполнена до конца.
Во FreeRTOS каждая задача имеет свой соб-
ственный стек и свой набор значений реги-
стров процессора. Если функция использует
переменные, расположенные только в стеке
или в регистрах процессора, то она является
реентерабельной. Напротив, функция, кото-
рая сохраняет свое состояние между вызова-
ми в статической или глобальной перемен-
ной, не является реентерабельной.
Таким образом, функция, которая зависит
только от своих параметров, не использует
глобальные и статические переменные и вы-
зывает только реентерабельные функции,
будет реентерабельной [4].
Одновременный вызов нереентерабель-
ной функции из нескольких задач может
привести к непредсказуемому результату.
Реентерабельными функциями можно поль-
зоваться, не опасаясь одновременного их вы-
зова из нескольких задач.
Рассмотрим пример реентерабельной
функции:
/* Параметр передается в функцию через регистр общего назначе-
ния или стек. Это безопасно, т. к. каждая задача имеет свой набор
регистров и свой стек. */
long lAddOneHundered( long lVar1 )
{
/* Объявлена локальная переменная. Компилятор расположит ее
или в регистре или в стеке в зависимости от уровня оптимизации.
Каждая задача и каждое прерывание, вызывающее эту функцию,
будет иметь свою копию этой локальной переменной. */
long lVar2;
/* Какие-то действия над аргументом и локальной переменной.
*/
lVar2 = lVar1 + 100;
/* Обычно возвращаемое значение также помещается либо в стек,
либо в регистр. */
return lVar2;
}
Теперь рассмотрим несколько нереентера-
бельных функций:
/* В этом случае объявлена глобальная переменная. Каждая зада-
ча, вызывающая функцию, которая использует эту переменную,
будет «иметь дело» с одной и той же копией этой переменной */
long lVar1;
/* Нереентерабельная функция 1 */
long lNonReentrantFunction1( void )
{
/* Какие-то действия с глобальной переменной. */
lVar1 += 10;
return lVar1;
}
/* Нереентерабельная функция 2 */
void lNonReentrantFunction2( void )
{
/* Переменная, объявленная как статическая. Компилятор рас-
положит ее не в стеке. Значит, каждая задача, вызывающая эту
функцию, будет «иметь дело» с одной и той же копией этой
переменной. */
static long lState = 0;
switch( lState ) { /* … */};
}
/* Нереентерабельная функция 3 */
long lNonReentrantFunction3( void )
{
/* Функция, которая вызывает нереентерабельную функцию,
также является нереентерабельной. */
return lNonReentrantFunction1() + 100;
}
Достарыңызбен бөлісу: |