GNU/Linux >> Belajar Linux >  >> Linux

Apakah errno thread-safe?

Ya, ini aman untuk benang. Di Linux, variabel errno global khusus untuk thread. POSIX mensyaratkan bahwa errno be threadsafe.

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

Di POSIX.1, errno didefinisikan sebagai variabel global eksternal. Tetapi definisi ini tidak dapat diterima dalam lingkungan multithreaded, karena penggunaannya dapat menghasilkan hasil yang tidak dapat ditentukan. Masalahnya adalah bahwa dua atau lebih utas dapat mengalami kesalahan, semuanya menyebabkan kesalahan yang sama disetel. Dalam keadaan ini, utas mungkin akan memeriksa kesalahan setelah diperbarui oleh utas lainnya.

Untuk menghindari nondeterminisme yang dihasilkan, POSIX.1c mendefinisikan ulangserrno sebagai layanan yang dapat mengakses nomor kesalahan per-thread sebagai berikut(ISO/IEC 9945:1-1996, §2.4):

Beberapa fungsi dapat memberikan nomor kesalahan dalam variabel yang diakses melalui simbol errno. Simbolerrno didefinisikan dengan menyertakan header , seperti yang ditentukan oleh Standar C ... Untuk setiap utas proses, nilai errno tidak akan terpengaruh oleh pemanggilan fungsi atau penugasan ke errno oleh utas lainnya.

Lihat juga http://linux.die.net/man/3/errno

errno adalah utas-lokal; mengaturnya di satu utas tidak memengaruhi nilainya di utas lainnya.


Ya

Errno bukan lagi variabel sederhana, ini adalah sesuatu yang kompleks di balik layar, khususnya agar thread-safe.

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

Kami dapat memeriksa ulang:

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

Di errno.h, variabel ini dideklarasikan sebagai extern int errno;

Inilah yang dikatakan standar C:

Makro errno tidak perlu menjadi pengidentifikasi objek. Itu mungkin meluas ke nilai yang dapat dimodifikasi yang dihasilkan dari panggilan fungsi (misalnya, *errno() ).

Umumnya, errno adalah makro yang memanggil fungsi yang menampilkan alamat nomor kesalahan untuk utas saat ini, lalu mendereferensikannya.

Inilah yang saya miliki di Linux, di /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

Pada akhirnya, ini menghasilkan kode seperti ini:

> 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. Kesalahan Server MySQL – “Tidak Dapat Membuat Utas Baru (errno 11)”

  2. Cara mencetak pthread_t

  3. strtok fungsi pengaman benang

  1. Thread ID vs Thread Handle

  2. Akses thread-local dari thread lain

  3. Apakah aman untuk bercabang dari dalam seutas benang?

  1. ID dari utas Python seperti yang dilaporkan oleh top

  2. Utas mana yang menangani sinyal?

  3. Cetak errno sebagai mnemonik?