threads pthread_create pthread hilos compile compilar c linux multithreading gcc

pthread_create - threads c++



¿Errno es seguro para subprocesos? (7)

En errno.h , esta variable se declara como extern int errno; así que mi pregunta es, ¿es seguro verificar el valor de errno después de algunas llamadas o usar perror () en el código de subprocesos múltiples? ¿Es esta una variable segura de subprocesos? Si no, ¿cuál es la alternativa?

Estoy usando linux con gcc en la arquitectura x86.


En errno.h, esta variable se declara como extern int errno;

Esto es lo que dice el estándar C:

El macro errno no necesita ser el identificador de un objeto. Podría expandirse a un valor l modificable resultante de una llamada a función (por ejemplo, *errno() ).

En general, errno es una macro que llama a una función que devuelve la dirección del número de error para el hilo actual, y luego la desreferencia.

Esto es lo que tengo en Linux, en /usr/include/bits/errno.h:

/* Function to get address of global `errno'' variable. */ extern int *__errno_location (void) __THROW __attribute__ ((__const__)); # if !defined _LIBC || defined _LIBC_REENTRANT /* When using threads, errno is a per-thread value. */ # define errno (*__errno_location ()) # endif

Al final, genera este tipo de código:

> cat essai.c #include <errno.h> int main(void) { errno = 0; return 0; } > gcc -c -Wall -Wextra -pedantic essai.c > objdump -d -M intel essai.o essai.o: file format elf32-i386 Disassembly of section .text: 00000000 <main>: 0: 55 push ebp 1: 89 e5 mov ebp,esp 3: 83 e4 f0 and esp,0xfffffff0 6: e8 fc ff ff ff call 7 <main+0x7> ; get address of errno in EAX b: c7 00 00 00 00 00 mov DWORD PTR [eax],0x0 ; store 0 in errno 11: b8 00 00 00 00 mov eax,0x0 16: 89 ec mov esp,ebp 18: 5d pop ebp 19: c3 ret


Errno ya no es una variable simple, es algo complejo detrás de escena, específicamente para que sea seguro para subprocesos.

Ver $ man 3 errno :

ERRNO(3) Linux Programmer’s Manual ERRNO(3) NAME errno - number of last error SYNOPSIS #include <errno.h> DESCRIPTION ... errno is defined by the ISO C standard to be a modifiable lvalue of type int, and must not be explicitly declared; errno may be a macro. errno is thread-local; setting it in one thread does not affect its value in any other thread.

Podemos verificarlo dos veces:

$ cat > test.c #include <errno.h> f() { g(errno); } $ cc -E test.c | grep ^f f() { g((*__errno_location ())); } $


Creo que la respuesta es "depende". Las bibliotecas de tiempo de ejecución de C Thread-safe generalmente implementan errno como una llamada a función (macro expandiéndose a una función) si está creando código enhebrado con los indicadores correctos.


En muchos sistemas Unix, compilar con -D_REENTRANT asegura que errno es seguro para subprocesos.

Por ejemplo:

#if defined(_REENTRANT) || _POSIX_C_SOURCE - 0 >= 199506L extern int *___errno(); #define errno (*(___errno())) #else extern int errno; /* ANSI C++ requires that errno be a macro */ #if __cplusplus >= 199711L #define errno errno #endif #endif /* defined(_REENTRANT) */


Esto es de <sys/errno.h> en mi Mac:

#include <sys/cdefs.h> __BEGIN_DECLS extern int * __error(void); #define errno (*__error()) __END_DECLS

Entonces errno ahora es una función __error() . La función se implementa para que sea segura para subprocesos.


Sí, es seguro para subprocesos. En Linux, la variable errno global es específica de subprocesos. POSIX requiere que errno sea seguro para los hilos.

Ver http://www.unix.org/whitepapers/reentrant.html

En POSIX.1, errno se define como una variable global externa. Pero esta definición es inaceptable en un entorno multiproceso, porque su uso puede dar como resultado resultados no deterministas. El problema es que dos o más subprocesos pueden encontrar errores, todos causan el mismo errno. En estas circunstancias, un hilo puede terminar revisando errno una vez que ya ha sido actualizado por otro hilo.

Para eludir el no determinismo resultante, POSIX.1c redefine errno como un servicio que puede acceder al número de error por subproceso de la siguiente manera (ISO / IEC 9945: 1-1996, §2.4):

Algunas funciones pueden proporcionar el número de error en una variable a la que se accede a través del símbolo errno. El símbolo errno se define al incluir el encabezado, según lo especificado por el estándar C ... Para cada subproceso de un proceso, el valor de errno no se verá afectado por llamadas a funciones o asignaciones a errno por otros subprocesos.

También vea http://linux.die.net/man/3/errno

errno es thread-local; configurarlo en un hilo no afecta su valor en ningún otro hilo.


, como se explica en la http://linux.die.net/man/3/errno y las otras respuestas, errno es una variable local thread.

Sin embargo , hay un detalle tonto que podría olvidarse fácilmente. Los programas deben guardar y restaurar el errno en cualquier manejador de señales que ejecute una llamada al sistema. Esto se debe a que la señal será manejada por uno de los hilos del proceso que podría sobreescribir su valor.

Por lo tanto, los controladores de señal deberían guardar y restaurar errno. Algo como:

void sig_alarm(int signo) { int errno_save; errno_save = errno; //whatever with a system call errno = errno_save; }