getenv()
getutxid()
rand()
dbm_delete()
getgrent()
getutxline()
readdir()
dbm_error()
getgrgid()
gmtime()
setenv()
dbm_fetch()
getgrnam()
hcreate()
setgrent()
dbm_firstkey()
gethostbyaddr()
hdestroy()
setkey()
dbm_nextkey()
gethostbyname()
hsearch()
setpwent()
dbm_open()
gethostent()
inet_ntoa()
setutxent()
dbm_store()
getlogin()
l64a()
strerror()
dirname()
getnetbyaddr()
lgamma()
strtok()
dlerror()
getnetbyname()
lgammaf()
ttyname()
drand48()
getnetent()
lgammal()
unsetenv()
ecvt()
getopt()
localeconv()
wcstombs()
encrypt()
getprotobyname()
localtime()
wctomb()
endgrent()
getprotobynumber()
lrand48()
endpwent()
getprotoent()
mrand48()
endutxent()
getpwent()
nftw()
Использование критических участков для реализации потоковой безопасности является значительным прорывом по сравнению с назначением каждой функции отдельного мьютекса. Однако этот подход все равно не очень эффективен, поскольку на закрытие и открытие мьютексов тоже тратятся ресурсы.
• Некоторые функции ввиду своего назначения должны получать доступ к глобальным структурам данных. В качестве характерного примера можно привести функции из библиотеки malloc, которые хранят в куче связный список со свободными блоками. Эти функции реализованы потокобезопасными с помощью мьютексов.
• Некоторые функции (созданные до изобретения потоков) имеют интерфейс, который делает их нереентерабельными по определению; причиной тому может быть возвращение указателей на хранилище, статически выделенное самой функцией, или использование статического хранилища для хранения информации между последовательными вызовами одних и тех же (или родственных) функций. К этой категории можно причислить большинство функций, описанных в табл. 31.1. Например, функция asctime() (см. подраздел 10.2.3) возвращает указатель на статически выделенный буфер, содержащий строку с датой и временем.
Для некоторых функций, имеющих нереентерабельные интерфейсы, в стандарте SUSv3 предусмотрены реентерабельные аналоги, имена которых заканчиваются суффиксом _r. Такие функции требуют от вызывающего потока выделить буфер и передать им его адрес; он будет использован для возвращения результата. Это позволяет вызывающему потоку применить для итогового буфера функции локальную переменную (находящуюся в стеке). Для этих целей в стандарт SUSv3 входят следующие функции: asctime_r(), ctime_r(), getgrgid_r(), getgrnam_r(), getlogin_r(), getpwnam_r(), getpwuid_r(), gmtime_r(), localtime_r(), rand_r(), readdir_r(), strerror_r(), strtok_r() и ttyname_r().
Некоторые реализации также предоставляют дополнительные реентерабельные аналоги для других традиционных функций. Например, библиотека glibc содержит функции crypt_r(), gethostbyname_r(), getservbyname_r(), getutent_r(), getutid_r(), getutline_r() и ptsname_r(). Однако переносимые приложения не могут полагаться на их наличие в других реализациях. В некоторых случаях эти реентерабельные аналоги не входят в стандарт SUSv3, поскольку существуют альтернативы, которые имеют преимущества по сравнению с традиционными функциями и тоже являются реентерабельными. Например, у функций gethostbyname() и getservbyname() есть современная реентерабельная альтернатива, getaddrinfo().
Иногда многопоточному приложению нужно сделать так, чтобы определенные процедуры инициализации выполнялись только один раз, независимо от количества создаваемых потоков. Например, вам может потребоваться инициализировать мьютекс специальными атрибутами, используя функцию pthread_mutex_init(), и это должно быть единовременное действие. Этого обычно легко достичь, если потоки создаются из главной программы — любые потоки, зависящие от инициализации, должны быть созданы после ее проведения. Однако это невозможно сделать в библиотечной функции, потому что перед ее первым запуском вызывающая программа может уже успеть создать потоки. Следовательно, библиотечной функции нужен механизм выполнения инициализации при первом вызове из любого потока.
Единовременная инициализация реализована в виде функции pthread_once().
#include
int pthread_once(pthread_once_t *
Возвращает 0 при успешном завершении или положительное число, если произошла ошибка