You are here

Thread Local Storage Pointers

Перевод может содержать ошибки. Читайте первоисточник: Thread Local Storage Pointers

Назад: [Более подробно...] Вверх: [Более подробно...] Вперёд: [Более подробно...]

 

Введение

Локальное хранилище потока, англ. "thread local storage" или TLS, позволяет разработчику приложения сохранять значение внутри блока управления задачей, англ. "task's control block" или TCB, делая это значение специфичным (локальным) для самой задачи, и позволяет каждой задаче иметь своё собственное уникальное значение.

Локальное хранилище потока чаще всего используется для хранения значения, которое в однопоточном приложении хранилось бы в глобальной переменной. Например, многие библиотеки включают в себя глобальную переменную errno. Если библиотечная функция возвращает вызывающей функции состояние ошибки, то вызывающая функция может проверить переменную errno, чтобы определить, в чём заключалась ошибка. В однопоточном приложении достаточно объявить errno как глобальную переменную, но в многопоточном приложении каждый тред (задача) должна иметь своё собственное уникальное значение errno, иначе одна задача может прочитать значение errno, которое было предназначено другой задаче.

 

Указатели локального хранилища потока (Thread Local Storage Pointers)

FreeRTOS предоставляет разработчику приложения гибкий механизм локального хранилища потока за счёт использования указателей локального хранилища потока.

Константа времени компиляции configNUM_THREAD_LOCAL_STORAGE_POINTERS определяет размер на задачу массива указателей (void*). Функция API vTaskSetThreadLocalStoragePointer() используется для установки значения внутри массива void-указателей, и функция API pvTaskGetThreadLocalStoragePointer() используется для чтения значения из массива void-указателей.

 

Локальные целые треда (Thread Local Integers)

Значения, которые имеют размер меньше или равный размеру void-указателя могут быть напрямую сохранены внутри массива указателей локального хранилища потока. Например, если sizeof( void* ) равно 4, то 32-битное значение может быть сохранено в переменной void-указателя, используя простое приведение для подавления предупреждения компилятора. Однако если sizeof( void* ) равно 2, то только 16-битное значение может быть сохранено напрямую.

/*----------------------------------------------------------------------------*/
/* Объявляем 32-битную переменную. */
uint32_t ulVariable;

/*----------------------------------------------------------------------------*/
/* Запись 32-битного значения 0x12345678 непосредственно по индексу 1 в массив
локального хранилища потока. Передача NULL в качестве хэндла задачи даёт эффект
записи в локальное хранилище потока вызывающей задачи. */
vTaskSetThreadLocalStoragePointer( NULL,  /* Хэндл задачи. */
                                   1,     /* Индекс в массиве. */
                                   ( void * ) 0x12345678 ); /* Значение */

/*----------------------------------------------------------------------------*/
/* Сохранение значения 32-битной переменной ulVariable по индексу 0 в массиве
локального хранилища потока вызывающей задачи. */
ulVariable = ERROR_CODE;
vTaskSetThreadLocalStoragePointer( NULL,  /* Хэндл задачи. */
                                   0,     /* Индекс в массиве. */
                                   ( void * ) ulVariable ); /* Значение */

/*----------------------------------------------------------------------------*/
/* Чтение значения, расположенного по индексу 5 в массиве локального хранилища
потока вызывающей задачи, в переменную ulVariable. */
ulVariable = ( uint32_t ) pvTaskGetThreadLocalStoragePointer( NULL, 5 );

Сохранение и извлечение 32-битных значений непосредственно по индексу в массиве локального хранилища потока.

 

Локальные структуры потока (Thread Local Structures)

В предыдущем примере значения хранились непосредственно в массиве локального хранилища потока. Следующий пример демонстрирует, как использовать значение в массиве в качестве указателя на структуру, которая существует в другом месте в памяти.

/*----------------------------------------------------------------------------*/
/* Определяем тип-структуру. */
typedef struct
{
    uint32_t ulValue1;
    uint32_t ulValue2;
} xExampleStruct;

/* Объявляем указатель на тип, который определили выше. */
xExampleStruct *pxStruct;

/* Создаём структуру для использования в этой задаче. */
pxStruct = pvPortMalloc( sizeof( xExampleStruct ) );

/* Задаём значения полям структуры. */
pxStruct->ulValue1 = 0;
pxStruct->ulValue2 = 1;

/*----------------------------------------------------------------------------*/
/* Сохраняем указатель на структуру по индексу 0 в массиве локального хранилища
потока вызывающей задачи. */
vTaskSetThreadLocalStoragePointer( NULL,  /* Хэндл задачи. */
                                   0,     /* Индекс в массиве. */
                                   ( void * ) pxStruct ); /* Указатель
                                                             на структуру */

/* Получаем указатель на структуру, используемую вызывающей задачей, считывая
его по индексу 0 из массива локального хранилища потока вызывающей задачи. */
pxStruct = ( xExampleStruct * ) pvTaskGetThreadLocalStoragePointer( NULL, 0 );
						

Хранение указателя на структуру в массиве локального хранилища потока вызывающей задачи

Hobby's category: