Библиотека сайта rus-linux.net
Цилюрик О.И. Linux-инструменты для Windows-программистов | ||
Назад | Библиотеки API POSIX | Вперед |
Данные потока
Собственные данные потока
Техника создания собственных данных потоков (thread specific data)
создаёт по одному экземпляру каждого вида данных. Стандарт POSIX
указывает, что это число видов данных (тип pthread_key_t
)
не превышает 128. Последовательность действий при создании TSD:
1. Поток запрашивает pthread_key_create()
для создания ключа доступа к блоку данных определённого
типа; если потоку нужно иметь несколько блоков данных разной
типизациии (назначения), он делает такой вызов нужное число раз.
2. Некоторая сложность здесь в том, что запросить
распределение ключа должен только один поток, первым достигший
точки распределения. Последующие потоки должны только воспользоваться
ранее распределённым значением ключа. Для разрешения этой сложности
вводится вызов pthread_once()
.
3. Теперь каждый поток, использующий блок данных,
должен запросить специфический экземпляр данных по
pthread_getspecific()
и, если он убеждается, что это NULL
,
то запросить распределение блока для этого значения ключа по
pthread_setspecific()
.
4. В дальнейшем поток (и все вызываемые из него функции) может
работать со своим экземпляром, запрашивая его по pthread_getspecific()
.
5. При завершении любого потока система уничтожает и
его экземпляр данных. При этом вызывается деструктор пользователя,
который устанавливается при создании ключа pthread_key_create()
.
Деструктор единый для всех экземпляров данных во всех потоках для
этого значения ключа (pthread_key_t
),
но он получает параметром значение указателя на экземпляр данных завершаемого потока.
Всё это гораздо легче показать на примере кода:
static pthread_key_t key; static pthread_once_t once = PTHREAD_ONCE_INIT; typedef struct data_bloc { // наш собственный тип данных //... } data_t; static void destructor( data_t *db ) { // деструктор собственных данных free( db ); } static void once_creator( void ) { // создаёт единый на процесс ключ для данных data_t pthread_key_create( &key, destructor ); } void* thread_proc( void *data ) { // функция потока pthread_once( &once, once_creator ); // гарантия единичности создания ключа if( pthread_getspecific( key ) == NULL ) pthread_setspecific( key, malloc( sizeof( data_t ) ) ); // теперь везде в вызываемых потоком функциях: data_t *db = pthread_getspecific( key ); // ... }
Далее пример показывает разного рода данные, используемые потоком: а). параметр, передаваемый функции потока в стеке (и точно так же локальные данные функции потока), б). глобальные данные доступные всем потокам, в). экземпляр собственных данных потока.
own.c : include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> static int global = 0; static pthread_key_t key; typedef struct data_bloc { // наш собственный тип данных pthread_t tid; } data_t; void put_msg( int param ) { printf( "global=%u , parameter=%u , own=%lu\n", global, param, ((data_t*)pthread_getspecific( key ))->tid ); } static pthread_once_t once = PTHREAD_ONCE_INIT; static void destructor( void* db ) { // деструктор собственных данных data_t *p = (data_t*)db; free( p ); } static void once_creator( void ) { // создаёт единый на процесс ключ для данных data_ pthread_key_create( &key, destructor ); } void* thread_proc( void *data ) { // функция потока int param = (int)data; global++; pthread_once( &once, once_creator ); // гарантия единичности создания ключа pthread_setspecific( key, malloc( sizeof( data_t ) ) ); data_t *db = pthread_getspecific( key ); db->tid = pthread_self(); put_msg( param ); return NULL; } int main( int argc, char **argv, char **envp ) { #define TCNT 5 pthread_t tid[ TCNT ]; int i; for( i = 0; i < TCNT; i++ ) pthread_create( &tid[ i ], NULL, thread_proc, (void*)( i + 1 ) ); for( i = 0; i < TCNT; i++ ). pthread_join( tid[ i ], NULL ); return( EXIT_SUCCESS ); }
... и весьма неожиданные и поучительные результаты выполнения такого примера (два последовательно выполненные прогона, которые существенно отличаются выполнением):
$ ./own global=1 , parameter=4 , own=3047005040 global=2 , parameter=3 , own=3057494896 global=3 , parameter=1 , own=3078474608 global=4 , parameter=5 , own=3036515184 global=5 , parameter=2 , own=3067984752 $ ./own global=4 , parameter=1 , own=3078527856 global=5 , parameter=4 , own=3042863984 global=4 , parameter=3 , own=3057548144 global=4 , parameter=2 , own=3068038000 global=5 , parameter=5 , own=3030383472
Предыдущий раздел: | Оглавление | Следующий раздел: |
Завершение потока | Сигналы в потоках |