2010-10-30 12 views
9

Necesito cambiar la configuración regional en el hilo para analizar un doble con strtod() correctamente, estoy usando setlocale() para esto (C++). ¿Es seguro para subprocesos?¿La función de seguridad de hilo de setlocale es?

Actualización: Otro problema. Cuando invoco setlocale() en mi función main() no afecta a otras rutinas más profundas. ¿¿¿Por qué??? Hay un montón de código, por lo que es problemático escribir el fragmento.

Respuesta

3

Debe consultar la documentación para la implementación que esté utilizando. Actualmente, C++ no especifica nada sobre los hilos, por lo que se reduce a la implementación (que aún no nos ha dicho).

Por ejemplo, mi página de manual de Linux para setlocale tiene el fragmento:

Esta cadena puede ser alojada en almacenamiento estático.

que no indica en absoluto que sea inseguro, pero sería muy cauteloso. Es probable que llamarlo con NULL (es decir, consultar) sería seguro para subprocesos, pero tan pronto como tenga un hilo que lo modifique, todas las apuestas estarán desactivadas.

Probablemente la más segura que hay que hacer (suponiendo que no es seguro para subprocesos) sería la de proteger a todas las llamadas a setlocale con un mutex y tienen una función especial para dar formato a los números a lo largo de las líneas de:

claim mutex 
curr = setlocale to specific value 
format number to string 
setlocale to curr 
release mutex 
return string 
+0

a got it, gracias – milo

+0

Las últimas actualizaciones de proyectos de manual de linux contienen información de seguridad de MT. Desplácese hacia abajo de la página a "ATRIBUTOS" para ver "MT inseguro const: locale env" que define la seguridad de la función. Este marcado fue parte de una colaboración de un año entre el proyecto linux man-pages y glibc para desarrollar dicho marcado para uso del desarrollador. Luego 'man 7 attributes' para ver cómo puedes trabajar con const: locale y env markup para intentar ponerlo a salvo. –

2

Para C++ 98 depende del compilador y en qué lib de tiempo de ejecución se selecciona y en qué se entiende exactamente por seguridad de subprocesos.

E.g. con MSVC y tiempo de ejecución multiproceso, debe estar seguro en el sentido de que setlocale sí lo es. Pero no creo que obtendrás un entorno por subproceso. Use setlocale para una configuración regional global, no una configuración regional por subproceso.

C++ 98 no trata el subprocesamiento (o, para el caso, las bibliotecas dinámicas).

7

La llamada a setlocale() puede no ser segura en cuanto a los hilos, pero la configuración de la configuración regional es por proceso, no por subproceso. Eso significa que incluso si setlocale() es seguro para subprocesos o usa un mutex para protegerse, el cambio aún actualizará la configuración regional actual para todos sus subprocesos.

Sin embargo, hay una alternativa por hilo: uselocale().

#include <xlocale.h> 

locale_t loc = newlocale(LC_ALL_MASK, "nl_NL", NULL); 
uselocale(loc); 
freelocale(loc) 
// Do your thing 

La configuración regional utiliza de conteo de referencias internas, por lo que es seguro para usted para liberarla después de que haya activado con newlocale().

+0

Más precisamente, la configuración regional * puede * ser por proceso, consulte https://msdn.microsoft.com/en-us/library/26c0tb7x.aspx – Lev

5

En C++ 11 los hilos estándar ahora son una parte admitida del lenguaje. La norma indica explícitamente que las llamadas setlocale() introducen carreras de datos con otras llamadas a setlocale() o llamadas a funciones que se ven afectadas por la configuración regional C actual, incluido strtod(). Se considera que la función locale :: global() se comporta como si llamara a setlocale(), por lo que también puede introducir una carrera de datos (se indica a continuación).

En Linux con glibc es MT-unsafe (const:locale env) que los hilos llaman a setlocale() simultáneamente con un argumento no NULO y llaman a cualquier otra función que pueda usar la configuración regional global (raza de datos y comportamiento indefinido en C11). Se sugiere utilizar uselocale() en su lugar, que es seguro para MT y cambia solo la configuración regional del hilo llamante. En Linux con libstdC++ en código C++, debe evitar locale :: global (cambio en todo el proceso) y crear una configuración regional para el uso del subproceso (la configuración regional :: global es MT insegura por las mismas razones que el tiempo de ejecución de C). Dado su objetivo de usar strtod (una C API) debe usar uselocale().

En Linux utilizando glibc, la función setlocale() en sí misma no es segura para MT a menos que cumpla 2 criterios estrictos, y según lo requiera POSIX, cambia la configuración regional para todo el proceso. Las nuevas páginas man de Linux (parte de Red Hat and Fujitsu work to specify MT-safety notations for all APIs) marcan setlocale() como "MT-Unsafe const: locale env", lo que significa que setlocale es MT-safe IFF mantiene la configuración regional constante (no modificándola, simplemente consultándola pasando NULL), y si mantiene constante la configuración regional y el entorno (para evitar cambios en la configuración regional si el argumento es ""). En Linux con glibc debe usar uselocale() si desea cambiar solo la configuración regional de la secuencia de llamada, ya que es seguro para MT y no depende de su entorno de ninguna manera y strtod utilizará la configuración regional del subproceso. De forma similar, todos los sistemas que implementan POSIX deben proporcionar uselocale() para usar en un contexto de subprocesos (MT-safe).

OS X implementa uselocale() para que pueda usar eso.

En Windows, use _configthreadlocale para cambiar si setlocale() opera en todo el proceso o subprocesos (lo convierte en uselocale que es lo que necesita), pero para el código C++ debe volver a use an instance of the locale class and avoid locale::global.

+0

En Windows debe usar el formato especial I18N funciona como GetDateFormatEx en lugar de strftime, etc. En macOS usa NSFormater incluso cuando no está haciendo las GUI de cocoa. En serio, la solución de los años 80 provista en Unix es terrible. – Lothar

+0

Buen escribir. ¿Tienes alguna referencia? –

+0

Se agregaron referencias al trabajo de páginas de manual aguas arriba y la página de manual de glibc con notas de seguridad de MT. –

0

Para hacer frente a la segunda parte de la pregunta original:

La función setlocale está en la biblioteca C (como se define en un entorno C++ por el encabezado estándar <clocale>) y su uso sólo afectará a rutinas de biblioteca C. Menciona C++ en la primera parte de su pregunta, por lo que me pregunto si espera que las rutinas de C++ tomen nota de los cambios locales realizados con setlocale. Mi experiencia dice que no lo harán.

Los métodos adecuados para tratar la información de la configuración regional en C++ están definidos por una biblioteca especificada en el encabezado estándar de C++ <locale>. Esta biblioteca proporciona control de la información de la configuración regional de una manera compatible con las operaciones de E/S de C++. Por ejemplo, puede crear un objeto std::locale con ciertas características y luego imbuir un std::filebuf con ese objeto para que las operaciones de E/S sigan esas características.

Si está ejecutando en un entorno mixto de C/C++, utilice std::locale::global() - con el tipo adecuado de los parámetros, sino que también establece la configuración regional global de C como si la función de biblioteca C setlocale fue llamado con LC_ALL. Esto mantendrá la funcionalidad de la biblioteca C y C++ sincronizada.