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
Sí
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.
sí , 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;
}