Страницы

Поиск по вопросам

суббота, 27 октября 2018 г.

Собственная глобальная переменная потока

Есть рабочая библиотека, которую необходимо использовать в многопоточном приложении. Все ошибки из вызовов данной библиотеки возвращаются через глобальную переменную, описанную в этой же библиотеке. Проанализировав код функций, становится понятно, что некоторую часть из них можно было бы беспрепятственно использовать в многопоточном приложении, если бы не эта глобальная переменная с кодом ошибки. Пока что мне приходилось в подобных случаях переписывать функции библиотеки, передавая в них указатель на переменную, куда сохранять код ошибки, это решение мне не нравится, так как ведет к полному перелопачиванию библиотеки.
Насколько мне известно, когда-то переменная errno тоже была глобальной для всей программы, но спустя некоторое время она была переопределена глобальной в пределах потока, т.е. для каждого потока выполнения она своя. Может ли кто-то подсказать, как проделать то же самое, или что-то близкое по смыслу с переменной кода ошибки в библиотеке, чтобы она была для каждого потока - своя, и чтобы не приходилось переписывать всю библиотеку?


Ответ

@margosh, немного почитал маны и вот что получилось (интересующую Вас переменную обозвал lib_errno, при создании (первое обращение к ней) в каждом потоке она обнуляется):
avp@avp-ubu1:hashcode$ more ptlib.h ptlib.c c.c | cat :::::::::::::: ptlib.h :::::::::::::: #ifndef _PTLIB_H #define _PTLIB_H
#ifdef __cplusplus extern "C" { #endif pid_t gettid(void); int *lib_errno_func(void); #ifdef __cplusplus } #endif #define lib_errno (*lib_errno_func())
#endif :::::::::::::: ptlib.c :::::::::::::: #include #include #include #include
#include #include
#include "ptlib.h"
pid_t gettid() { return syscall(SYS_gettid); }
static pthread_once_t key_is_initialized = PTHREAD_ONCE_INIT; static pthread_key_t key;
static void destruct_thread_value (void *ptr) { printf("destruct: %ld %p value %d
", (long)gettid(), ptr, ptr ? *((int *)ptr) : 0); free(ptr); }
static void make_key () { printf("make_key: %ld
", (long)gettid()); pthread_key_create(&key, destruct_thread_value); }
int * lib_errno_func () { int *ptr;
pthread_once(&key_is_initialized, make_key); if (!(ptr = (typeof(ptr))pthread_getspecific(key))) { ptr = (typeof(ptr))calloc(sizeof(int), 1); printf("construct: %ld %p
", (long)gettid(), ptr); pthread_setspecific(key, ptr); }
return ptr; }
:::::::::::::: c.c :::::::::::::: #include #include #include #include
#include "ptlib.h"
void * tfunc (void *a) { usleep(rand() % 100000); printf("thread-run: tid=%ld a=%d lib_errno=%d
", (long)gettid(), *((int *)a), lib_errno); lib_errno = *((int *)a) + 100; usleep(rand() % 100000); printf("thread-fin: tid=%ld a=%d lib_errno=%d
", (long)gettid(), *((int *)a), lib_errno);
return 0; }
int main (int ac, char *av[]) { int n = atoi(av[1] ? av[1] : "3"); if (n < 1) n = 3; pthread_t tid[n];
printf("main-run: tid=%ld lib_errno=%d
", (long)gettid(), lib_errno);
int i; for (i = 0; i < n; i++) { int *pv = (int *)malloc(sizeof(int)); *pv = i; pthread_create(tid + i, 0, tfunc, pv); }
for (i = 0; i < n; i++) pthread_join(tid[i], 0);
printf("main-fin: tid=%ld lib_errno=%d
", (long)gettid(), lib_errno);
return puts("End") == EOF; } avp@avp-ubu1:hashcode$ gcc -pthread -O2 -c ptlib.c -Wall avp@avp-ubu1:hashcode$ g++ -pthread c.c ptlib.o avp@avp-ubu1:hashcode$ ./a.out make_key: 5556 construct: 5556 0x8ca010 main-run: tid=5556 lib_errno=0 construct: 5558 0x7f22c40008c0 thread-run: tid=5558 a=1 lib_errno=0 thread-fin: tid=5558 a=1 lib_errno=101 destruct: 5558 0x7f22c40008c0 value 101 construct: 5557 0x7f22c40008c0 thread-run: tid=5557 a=0 lib_errno=0 construct: 5559 0x7f22bc0008c0 thread-run: tid=5559 a=2 lib_errno=0 thread-fin: tid=5559 a=2 lib_errno=102 destruct: 5559 0x7f22bc0008c0 value 102 thread-fin: tid=5557 a=0 lib_errno=100 destruct: 5557 0x7f22c40008c0 value 100 main-fin: tid=5556 lib_errno=0 End avp@avp-ubu1:hashcode$ avp@avp-ubu1:hashcode$
На первый взгляд, вроде работает...

Комментариев нет:

Отправить комментарий