GNU/Linux >> Znalost Linux >  >> Linux

Je errno vlákno bezpečné?

Ano, je to vlákno bezpečné. V Linuxu je globální proměnná errno specifická pro vlákno. POSIX vyžaduje, aby errno bylo bezpečné pro vlákna.

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

V POSIX.1 je errno definováno jako externí globální proměnná. Ale tato definice je nepřijatelná v prostředí s více vlákny, protože její použití může vést k nedeterministickým výsledkům. Problém je v tom, že dvě nebo více vláken může narazit na chyby, které způsobí nastavení stejného errno. Za těchto okolností může vlákno skončit kontrolou errno poté, co již bylo aktualizováno jiným vláknem.

Aby se předešlo výslednému nedeterminismu, POSIX.1c předefinuje jako službu, která má přístup k číslu chyby pro vlákno následovně (ISO/IEC 9945:1-1996, §2.4):

Některé funkce mohou poskytnout číslo chyby v proměnné přístupné prostřednictvím symbolu errno. Symbolerrno je definováno zahrnutím záhlaví, jak je specifikováno standardem C... Pro každé vlákno procesu nesmí být hodnota errno ovlivněna voláním funkcí nebo přiřazením k errno jinými vlákny.

Viz také http://linux.die.net/man/3/errno

errno je místní vlákno; jeho nastavení v jednom vlákně neovlivní jeho hodnotu v žádném jiném vlákně.


Ano

Errno už není jednoduchá proměnná, je to něco složitého v zákulisí, konkrétně proto, aby byla bezpečná pro vlákna.

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

Můžeme znovu zkontrolovat:

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

V errno.h je tato proměnná deklarována jako extern int errno;

Zde je to, co říká standard C:

Makro errno nemusí být identifikátorem objektu. Může se rozšířit na modifikovatelnou lvalue vyplývající z volání funkce (například *errno() ).

Obecně errno je makro, které volá funkci vracející adresu čísla chyby pro aktuální vlákno a poté ji dereferencuje.

Zde je to, co mám na Linuxu, v /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

Nakonec vygeneruje tento druh kódu:

> 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. Jak ukončit vlákno v programu C ( příklad pthread_exit )

  2. Jak vytisknout pthread_t

  3. funkce strtok bezpečnost vlákna

  1. Je bezpečné forkovat z vlákna?

  2. ID vlákna Pythonu, jak je uvedeno nahoře

  3. Které vlákno zpracovává signál?

  1. Chyba serveru MySQL – „Nelze vytvořit nové vlákno (chyba 11)“

  2. Jak pojmenovat vlákno v Linuxu?

  3. Print errno jako mnemotechnická pomůcka?