Hacer que las variables estáticas globales multithread seguras
-
27-09-2019 - |
Pregunta
Tengo variables estáticas globales en una biblioteca C, que generan excepciones en una ejecución múltiple. Necesito hacerlos seguros de alguna manera (es decir, cada hilo debe relacionarse con una instancia diferente de estas variables). ¿Algún método recomendado?
Solución
No existe una forma estándar que funcione en todas las implementaciones de C, pero existen soluciones específicas de implementación. Por ejemplo, con el compilador de Microsoft (ver los documentos),
__declspec( thread ) int tls_i = 1;
hace tls_i
Live en el almacenamiento de hilo-local (cada hilo tiene su propia instancia separada de esta variable). Con GCC, la sintaxis es
__thread int tls_i;
También es posible que desee verificar el Entrada de Wikipedia sobre el tema.
Otros consejos
Primera pregunta:
- ¿Los hilos necesitan sus propias copias de las variables?
- ¿O necesitan coordinar el acceso a una sola copia compartida?
Si necesita el primero, las otras respuestas han hecho sugerencias sobre el 'almacenamiento local de hilos'.
Si necesita este último, de alguna manera u otro debe asegurarse de que haya un mutex apropiado en esas variables (el alcance del mutex es uno de los problemas que enfrenta), y que todos los hilos usan el mutex y liberan el mutex. Esto es más complicado. Incluso puede ser que necesite proporcionar funciones que controlen el acceso a las variables.
La variable estándar errno
puede ser un LValue modificable:
extern int *_errno_func(void);
#define errno (*(_errno_func)())
En una aplicación roscada (compilada con -dreentrant), esto es lo que sucede; En MacOS X, parece ser lo que sucede de todos modos (usan el nombre __error
en vez de _errno_func
; Ambos están en el espacio de nombres de la implementación).
Es posible que desee o termine teniendo que hacer algo similar para sus variables. El hecho de que digas que son estáticos mejora un poco las cosas. Solo tiene un archivo con el que tratar (a menos que sea lo suficientemente descuidado como para retroceder o encender a esas variables).
Lo que necesitabas es TLS (almacenamiento local de subprocesos), que también se conoce como datos específicos de hilo o datos-privados de hilo. Este mecanismo puede garantizar que cada hilo acceda a su propia copia separada de datos, sin preocuparse por sincronizar el acceso con otros hilos.
Hay dos métodos para usar TLS:
Implícito: Uso de la palabra clave
Windows: __DeclSpec (Thread) int tls_var = 10;
Linux con GCC: __Thread int tls_var = 10
Explícito: usando una API relacionada con TLS específica
Windows:
- Tlsalloc (): Asignar memoria para los datos de TLS
- Tlsfree (): liberar la memoria de los datos de TLS
- TlssetValue (): Establecer el valor de TLS
- TlsgetValue (): Obtener el valor de TLS
Consulte MSDN para obtener información detallada.
Linux con GCC:
- pthread_key_create (): Cree los datos de TLS
- pthread_key_delete (): Destory Los datos de TLS
- pthread_getSpecific (): Obtener el valor de TLS
- pthread_setspecífico(): establecer el valor de TLS
La mayoría de los compiladores tienen alguna forma de designar el almacenamiento local de subprocesos. Suponiendo que está disponible, eso es lo que quieres.