Обеспечение безопасности многопоточности глобальных статических переменных
-
27-09-2019 - |
Вопрос
У меня есть глобальные статические переменные в библиотеке C, которые генерируют исключения при многопоточном запуске.Мне нужно каким-то образом сделать их безопасными (т. е. каждый поток должен относиться к другому экземпляру этих переменных).Какие-нибудь рекомендуемые методы?
Решение
Нет стандартного способа, который работает во всех реализациях C, но существуют решения, специфичные для реализации. Например, с компилятором Microsoft (см. Документы),
__declspec( thread ) int tls_i = 1;
произносить tls_i
Live в потоке - локальное хранилище (каждый поток имеет свой отдельный экземпляр этой переменной). С участием GCC., синтаксис
__thread int tls_i;
Вы также можете проверить Вход в Википедии по теме.
Другие советы
Первый вопрос:
- нужны ли потокам собственные копии переменных?
- или им нужно координировать доступ к одной общей копии?
Если вам нужно первое, в других ответах были сделаны предложения о "локальном хранилище потоков".
Если вам нужно последнее, то так или иначе вам нужно убедиться, что для этих переменных есть соответствующий мьютекс (область действия мьютекса является одной из проблем, с которыми вы сталкиваетесь), и что все потоки используют мьютекс и освобождают мьютекс.Это гораздо сложнее.Возможно даже, что вам нужно предоставить функции, управляющие доступом к переменным.
Стандартная переменная errno
может быть изменяемым значением lvalue:
extern int *_errno_func(void);
#define errno (*(_errno_func)())
В потоковом приложении (скомпилированном с помощью -DREENTRANT) происходит вот что;в macOS X, похоже, это то, что происходит в любом случае (они используют название __error
вместо того, чтобы _errno_func
;оба находятся в пространстве имен реализации).
Возможно, вы захотите или в конечном итоге вам придется сделать что-то подобное для ваших переменных.Тот факт, что вы говорите, что они статичны, немного улучшает ситуацию.У вас есть только один файл для работы (если только вы не настолько неосторожны, чтобы передавать указатели назад или на эти переменные).
Что вам нужно, это TLS (поток локального хранения), который также известен как данные с нитью данные или Нить-частные данные. Отказ Этот механизм может гарантировать каждому потоку для доступа к своей отдельной копии данных, не беспокоясь о синхронизации доступа с другими потоками.
Существует два метода для использования TLS:
неявный: с использованием ключевого слова
Windows: __declspec (поток) int tls_var = 10;
Linux с GCC: __thread int tls_var = 10
явное: с использованием конкретных TLS, связанных с API
Windows:
- Tlsalloc (): выделить память для данных TLS
- Tlsfree (): Бесплатно память данных TLS
- TlsSetValue (): Установите значение TLS
- TlsgetValue (): получить значение TLS
Пожалуйста, обратитесь к MSDN для получения подробной информации.
Linux с GCC:
- pthread_key_create (): Создайте данные TLS
- pthread_key_delete (): Destory Data TLS
- pthread_getspecific (): получить значение TLS
- pthread_setspecific(): установить значение TLS
Большинство компиляторов имеют какой-то способ назначения ниток-локального хранения. Предполагая, что это доступно, вот что вы хотите.