Простой. Когда я использую его, это - современный динамический язык при использовании его это - просто язык сценариев!
Да, это потокобезопасность. В Linux глобальная переменная errno зависит от потока. POSIX требует, чтобы errno была потокобезопасной.
См. http://www.unix.org/whitepapers/reentrant.html
В POSIX.1 errno определяется как внешняя глобальная переменная. Но это определение неприемлемо в многопоточная среда, потому что ее использование может привести к недетерминированным полученные результаты. Проблема в том, что два или больше потоков могут столкнуться с ошибками, все вызывая установку того же errno. В этих условиях нить может закончиться проверкой errno после этого уже обновлен другим thread.
Чтобы обойти полученный недетерминизм, POSIX.1c переопределяет errno как сервис, который может получить доступ к номер ошибки для потока следующим образом (ISO / IEC 9945: 1-1996, §2.4):
Некоторые функции могут предоставлять номер ошибки в переменной, к которой осуществляется доступ через символ errno. Символ errno определяется включением заголовок, как указано в C Стандартный ... Для каждой резьбы процесса, значение errno не должно быть затронутыми вызовами функций или присвоение errno другим потокам.
См. также http://linux.die.net/man/3/errno
errno является локальным потоком; установка его в одном потоке не влияет на его значение в любом другом потоке.
В errno.h эта переменная объявлена как extern int errno;
Вот что говорит стандарт C:
Макрос
errno
не обязательно идентификатор объекта. Он может расширяться до изменяемого lvalue в результате вызова функции (например,* errno ()
).
Как правило, errno
- это макрос, который вызывает функцию, возвращающую адрес номера ошибки для текущего потока, затем разыменовывает его.
Вот то, что у меня есть в Linux, в /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
В конце он генерирует такой код:
> 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
Во многих системах Unix компиляция с помощью -D_REENTRANT
гарантирует, что errno
является потокобезопасным.
Например:
#if defined(_REENTRANT) || _POSIX_C_SOURCE - 0 >= 199506L
extern int *___errno();
#define errno (*(___errno()))
#else
extern int errno;
/* ANSI C++ requires that errno be a macro */
#if __cplusplus >= 199711L
#define errno errno
#endif
#endif /* defined(_REENTRANT) */
Это из
на моем Mac:
#include <sys/cdefs.h>
__BEGIN_DECLS
extern int * __error(void);
#define errno (*__error())
__END_DECLS
Итак, errno
теперь является функцией __ error ()
. Функция реализована так, чтобы быть потокобезопасной.
Errno больше не простая переменная, это что-то сложное за кулисами, особенно для обеспечения потоковой безопасности.
См. $ 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.
Мы можем перепроверить:
$ cat > test.c
#include <errno.h>
f() { g(errno); }
$ cc -E test.c | grep ^f
f() { g((*__errno_location ())); }
$
Думаю, ответ - «это зависит от обстоятельств». Поточно-ориентированные библиотеки времени выполнения C обычно реализуют errno как вызов функции (макрос, расширяющийся до функции), если вы создаете многопоточный код с правильными флагами.