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