GNU/Linux >> Linux Esercitazione >  >> Linux

errno è thread-safe?

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.


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

Linux
  1. I thread hanno un heap distinto?

  2. Come stampare pthread_t

  3. Thread POSIX staccati e unibili

  4. ID thread e handle del thread

  5. Accedi al thread locale da un altro thread

Come nominare un thread in Linux?

WaitForSingleObject e WaitForMultipleObjects equivalenti in Linux?

funzione strtok thread safety

È sicuro eseguire il fork dall'interno di un thread?

Quale thread gestisce il segnale?

Stampa errno come mnemonico?