В errno.h
, эта переменная объявлена так, extern int errno;
поэтому мой вопрос: безопасно ли проверять errno
значение после некоторых вызовов или использовать perror () в многопоточном коде. Это потокобезопасная переменная? Если нет, то какая альтернатива?
Я использую Linux с GCC на архитектуре x86.
c
linux
multithreading
gcc
Винит Дхатрак
источник
источник
Ответы:
Да, это потокобезопасно. В Linux глобальная переменная errno зависит от потока. POSIX требует, чтобы errno был безопасен для потоков.
См. Http://www.unix.org/whitepapers/reentrant.html.
Также см. Http://linux.die.net/man/3/errno
источник
# if !defined _LIBC || defined _LIBC_REENTRANT
, _LIBC не определяется при компиляции обычных программ. В любом случае, запустите echo#include <errno.h>' | gcc -E -dM -xc -
и посмотрите на разницу с и без -pthread. errno#define errno (*__errno_location ())
в обоих случаях.да
Errno больше не простая переменная, это нечто сложное за кулисами, специально для того, чтобы оно было поточно-ориентированным.
Смотрите
$ man 3 errno
:Мы можем перепроверить:
источник
Вот что говорит стандарт C:
Обычно
errno
это макрос, который вызывает функцию, возвращающую адрес номера ошибки для текущего потока, а затем разыменовывает его.Вот что у меня есть в Linux, в /usr/include/bits/errno.h:
В конце концов, он генерирует такой код:
источник
Во многих системах Unix компиляция с
-D_REENTRANT
гарантирует, чтоerrno
это потокобезопасно.Например:
источник
-D_REENTRANT
. Пожалуйста, обратитесь к обсуждению другого ответа на тот же вопрос.-D_XOPEN_SOURCE=500
или-D_XOPEN_SOURCE=600
. Не каждый заботится о том, чтобы среда POSIX была указана, а затем-D_REENTRANT
может сохранить бекон. Но вы все равно должны быть осторожны - на каждой платформе - чтобы гарантировать, что вы получите желаемое поведение.errno
который расширяется до модифицируемого lvalue (201), который имеет типint
и продолжительность локального хранилища потока, значение которого устанавливается в положительное число ошибки несколькими библиотечными функциями. Если определение макроса подавлено, чтобы получить доступ к реальному объекту, или программа определяет идентификатор с именемerrno
, поведение не определено. [... продолжение ...]errno
не должен быть идентификатором объекта. Он может расширяться до модифицируемого lvalue, получаемого в результате вызова функции (например,*errno()
). Основной текст продолжается: значение errno в начальном потоке равно нулю при запуске программы (начальное значение errno в других потоках является неопределенным значением), но никогда не устанавливается равным нулю какой-либо библиотечной функцией. POSIX использует стандарт C99, который не распознает потоки. [... также продолжение ...]Это из
<sys/errno.h>
моего Mac:Так
errno
что теперь функция__error()
. Функция реализована так, чтобы быть поточно-ориентированной.источник
да , как объясняется на странице руководства errno и в других ответах, errno является локальной переменной потока.
Однако есть глупая деталь, о которой можно легко забыть. Программы должны сохранять и восстанавливать ошибки в любом обработчике сигналов, выполняющем системный вызов. Это связано с тем, что сигнал будет обрабатываться одним из потоков процесса, который может перезаписать его значение.
Поэтому обработчики сигналов должны сохранять и восстанавливать ошибки. Что-то вроде:
источник
Я думаю, что ответ "это зависит". Поточно-ориентированные библиотеки времени выполнения C обычно реализуют errno как вызов функции (расширение макроса до функции), если вы создаете многопоточный код с правильными флагами.
источник
Мы можем проверить, запустив простую программу на машине.
Запуск этой программы, и вы можете увидеть разные адреса для errno в каждом потоке. Вывод пробега на моей машине выглядел так:
Обратите внимание, что адрес отличается для всех потоков.
источник