Sì, è thread-safe. Su Linux, la variabile globale errno è specifica del thread. POSIX richiede che errno sia thread-safe.
Vedere http://www.unix.org/whitepapers/reentrant.html
In POSIX.1, errno è definito come una variabile globale esterna. Ma questa definizione è inaccettabile in un ambiente multithread, perché il suo utilizzo può portare a risultati non deterministici. Il problema è che due o più thread possono riscontrare errori, causando tutti l'impostazione dello stesso errno. In queste circostanze, un thread potrebbe finire per controllare errno dopo che è già stato aggiornato da un altro thread.
Per aggirare il non determinismo risultante, POSIX.1c ridefinisce serrno come un servizio che può accedere al numero di errore per thread come segue (ISO/IEC 9945:1-1996, §2.4):
Alcune funzioni possono fornire il numero di errore in una variabile a cui si accede tramite il simbolo errno. Il symbolerrno è definito includendo l'intestazione , come specificato dallo standard C ... Per ogni thread di un processo, il valore di errno non deve essere influenzato dalle chiamate di funzione o dalle assegnazioni a errno da parte di altri thread.
Vedi anche http://linux.die.net/man/3/errno
errno è thread-local; impostarlo in un thread non influisce sul suo valore in nessun altro thread.
Sì
Errno non è più una semplice variabile, è qualcosa di complesso dietro le quinte, specifico per essere thread-safe.
Vedi $ 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.
Possiamo ricontrollare:
$ cat > test.c
#include <errno.h>
f() { g(errno); }
$ cc -E test.c | grep ^f
f() { g((*__errno_location ())); }
$
In errno.h, questa variabile è dichiarata come extern int errno;
Ecco cosa dice lo standard C:
La macro
errno
non deve essere l'identificatore di un oggetto. Potrebbe espandersi in un lvalue modificabile risultante da una chiamata di funzione (ad esempio,*errno()
).
Generalmente, errno
è una macro che chiama una funzione che restituisce l'indirizzo del numero di errore per il thread corrente, quindi lo dereferenzia.
Ecco cosa ho su Linux, in /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
Alla fine, genera questo tipo di codice:
> 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