GNU/Linux >> Tutoriels Linux >  >> Linux

Est-ce que errno est thread-safe ?

Oui, il est thread-safe. Sous Linux, la variable globale errno est spécifique au thread. POSIX exige que errno soit thread-safe.

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

Dans POSIX.1, errno est défini comme une variable globale externe. Mais cette définition est inacceptable dans un environnement multithread, car son utilisation peut entraîner des résultats non déterministes. Le problème est que deux threads ou plus peuvent rencontrer des erreurs, provoquant toutes la définition du même errno. Dans ces circonstances, un thread peut finir par vérifier errno après avoir déjà été mis à jour par un autre thread.

Pour contourner le non-déterminisme qui en résulte, POSIX.1c redéfinit errno en tant que service pouvant accéder au numéro d'erreur par thread comme suit (ISO/IEC 9945:1-1996, §2.4) :

Certaines fonctions peuvent fournir le numéro d'erreur dans une variable accessible via le symbole errno. Le symbole errno est défini en incluant l'en-tête , tel que spécifié par la norme C... Pour chaque thread d'un processus, la valeur de errno ne doit pas être affectée par les appels de fonction ou les affectations à errno par d'autres threads.

Voir aussi http://linux.die.net/man/3/errno

errno est local au thread ; le définir dans un thread n'affecte pas sa valeur dans un autre thread.


Oui

Errno n'est plus une simple variable, c'est quelque chose de complexe dans les coulisses, spécifiquement pour qu'elle soit thread-safe.

Voir $ 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.

Nous pouvons vérifier :

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

Dans errno.h, cette variable est déclarée comme extern in errno ;

Voici ce que dit la norme C :

La macro errno n'a pas besoin d'être l'identifiant d'un objet. Il peut s'étendre à une lvalue modifiable résultant d'un appel de fonction (par exemple, *errno() ).

Généralement, errno est une macro qui appelle une fonction retournant l'adresse du numéro d'erreur du thread en cours, puis le déréférence.

Voici ce que j'ai sous Linux, dans /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

Au final, il génère ce genre de code :

> 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. Comment terminer un thread dans un programme C ( exemple pthread_exit )

  2. Erreur du serveur MySQL - "Impossible de créer un nouveau fil (errno 11)"

  3. Les threads ont-ils un tas distinct ?

  4. Comment imprimer pthread_t

  5. sécurité des threads de la fonction strtok

WaitForSingleObject et WaitForMultipleObjects équivalent sous Linux ?

Threads POSIX détachés ou joignables

ID de thread vs poignée de thread

Ouverture d'un thread Python dans une nouvelle fenêtre de console

Connexion refusée à MongoDB errno 111

Que se passe-t-il lorsqu'un thread bifurque ?