Apache. Документация на русском


Разделы:   1    2    3    4    5    6    7    8    9    10      11      12    13    14    15    16  

Раздел 11. Документация для разработчиков

Пункты:   214    215    216    217    218    219    220    221    222      223    

 <         > 
  RU            EN  

Пункт 223. Проблемы безопасности потоков в версии 2.x

При использовании любого из многопоточных mpms в Apache HTTP Server 2.x важно, чтобы каждая функция, вызываемая из Apache, была потокобезопасной. При связывании сторонних расширений может быть сложно определить, будет ли результирующий сервер потокобезопасным. Случайное тестирование, как правило, также не скажет вам об этом, поскольку проблемы с безопасностью потоков могут привести к тонким состояниям гонки, которые могут проявляться только в определенных условиях при большой нагрузке.

Глобальные и статические переменные

При написании модуля или при попытке определить, является ли модуль или сторонняя библиотека потокобезопасным, необходимо помнить о некоторых общих вещах.

Во-первых, вам нужно признать, что в многопоточной модели каждый отдельный поток имеет свой счетчик программ, стек и регистры. Локальные переменные живут в стеке, так что все в порядке. Вам нужно следить за любыми статическими или глобальными переменными. Это не означает, что вам абсолютно запрещено использовать статические или глобальные переменные. Бывают случаи, когда вы действительно хотите, чтобы что-то влияло на все потоки, но обычно вам нужно избегать их использования, если вы хотите, чтобы ваш код был потокобезопасным.

Если у вас есть глобальная переменная, которая должна быть глобальной и доступной для всех потоков, будьте очень осторожны при ее обновлении. Если, например, это инкрементный счетчик, вам нужно увеличить его атомарно, чтобы избежать условий гонки с другими потоками. Вы делаете это, используя мьютекс (взаимное исключение). Заблокируйте мьютекс, прочитайте текущее значение, увеличьте его и запишите обратно, а затем разблокируйте мьютекс. Любой другой поток, который хочет изменить значение, должен сначала проверить мьютекс и заблокировать его, пока он не будет очищен.

Если вы используете APR, взгляните на функции и функции. apr_atomic_* apr_thread_mutex_*

ошибаться

Это общая глобальная переменная, которая содержит номер последней возникшей ошибки. Если один поток вызывает низкоуровневую функцию, которая устанавливает errno, а затем другой поток проверяет ее, мы передаем номера ошибок из одного потока в другой. Чтобы решить эту проблему, убедитесь, что ваш модуль или библиотека определяет _REENTRANT или скомпилирована с расширением -D_REENTRANT . Это сделает errno переменной для каждого потока и, надеюсь, должно быть прозрачно для кода. Он делает это, делая что-то вроде этого:

#define errno (*(__errno_location()))

это означает, что доступ к errno вызовет вызов __errno_location() , который предоставляется libc. Параметр _REENTRANT также вызывает переопределение некоторых других функций на их эквиваленты и иногда изменяет общие макросы / на более безопасные вызовы функций. Подробности смотрите в документации по libc. Вместо или в дополнение к символам, которые могут повлиять на это, используются , , и . *_r getc putc _REENTRANT _POSIX_C_SOURCE _THREAD_SAFE _SVID_SOURCE _BSD_SOURCE

Общие стандартные проблемные функции

Вещи должны быть не только потокобезопасными, но и реентерабельными. strtok() является очевидным. Вы вызываете его в первый раз со своим разделителем, который затем запоминается, и при каждом последующем вызове он возвращает следующий токен. Очевидно, что если его вызывают несколько потоков, у вас возникнут проблемы. В большинстве систем есть реентерабельная версия функции, вызываемой strtok_r() в которой вы передаете дополнительный аргумент, содержащий выделенную область char * , которую функция будет использовать вместо своего собственного статического хранилища для поддержания состояния токенизации. Если вы используете APR, вы можете использовать apr_strtok() .

crypt() — это еще одна функция, которая, как правило, не является реентерабельной, поэтому, если вы столкнетесь с вызовами этой функции в библиотеке, будьте осторожны. Однако в некоторых системах он реентерабельный, так что это не всегда проблема. Если у вашей системы есть crypt_r() шансы, вам следует использовать это или, если возможно, просто избежать всего беспорядка, используя вместо этого md5.

Общие сторонние библиотеки

Ниже приведен список общих библиотек, которые используются сторонними модулями Apache. Вы можете проверить, не использует ли ваш модуль потенциально небезопасную библиотеку, используя такие инструменты, как ldd(1) и nm(1) . Например, для PHP попробуйте следующее:

% ldd libphp4.so
libsablot.so.0 => /usr/local/lib/libsablot.so.0 (0x401f6000)
libexpat.so.0 => /usr/lib/libexpat.so.0 (0x402da000)
libsnmp.so.0 => /usr/lib/libsnmp.so.0 (0x402f9000)
libpdf.so.1 => /usr/local/lib/libpdf.so.1 (0x40353000)
libz.so.1 => /usr/lib/libz.so.1 (0x403e2000)
libpng.so.2 => /usr/lib/libpng.so.2 (0x403f0000)
libmysqlclient.so.11 => /usr/lib/libmysqlclient.so.11 (0x40411000)
libming.so => /usr/lib/libming.so (0x40449000)
libm.so.6 => /lib/libm.so.6 (0x40487000)
libfreetype.so.6 => /usr/lib/libfreetype.so.6 (0x404a8000)
libjpeg.so.62 => /usr/lib/libjpeg.so.62 (0x404e7000)
libcrypt.so.1 => /lib/libcrypt.so.1 (0x40505000)
libssl.so.2 => /lib/libssl.so.2 (0x40532000)
libcrypto.so.2 => /lib/libcrypto.so.2 (0x40560000)
libresolv.so.2 => /lib/libresolv.so.2 (0x40624000)
libdl.so.2 => /lib/libdl.so.2 (0x40634000)
libnsl.so.1 => /lib/libnsl.so.1 (0x40637000)
libc.so.6 => /lib/libc.so.6 (0x4064b000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x80000000)

В дополнение к этим библиотекам вам нужно будет взглянуть на любые библиотеки, статически связанные с модулем. Вы можете использовать nm(1) для поиска отдельных символов в модуле.

Список библиотек

Пожалуйста, напишите на dev@httpd.apache.org, если у вас есть дополнения или исправления к этому списку.

БиблиотекаВерсияПоток безопасный?Примечания
ASpell/PSpell ?
Беркли БД 3.х, 4.х Да Будьте осторожны при совместном использовании соединения между потоками.
bzip2 Да Как низкоуровневые, так и высокоуровневые API являются потокобезопасными. Однако высокоуровневый API требует потокобезопасного доступа к errno.
CDB ?
C-клиент Возможно c-client strtok() и gethostbyname() которые не являются потокобезопасными в большинстве реализаций библиотеки C. Статические данные c-client предназначены для совместного использования между потоками. Если strtok() и gethostbyname() являются потокобезопасными в вашей ОС, c-client может быть потокобезопасным.
либкрипт ?
Экспат Да Нужен отдельный экземпляр парсера для каждого потока
FreeTDS ?
Свободный тип ?
ГД 1.8.х ?
ГД 2.0.х ?
gdbm Нет Ошибки, возвращаемые через статическую gdbm_error переменную
ImageMagick 5.2.2 Да Документы ImageMagick утверждают, что он является потокобезопасным, начиная с версии 5.2.2 (см. Журнал изменений).
Imlib2 ?
libjpeg v6b ?
libmysqlclient Да Используйте вариант библиотеки mysqlclient_r для обеспечения потокобезопасности. Для получения дополнительной информации, пожалуйста, прочитайте http://dev.mysql.com/doc/mysql/en/Threaded_clients.html.
Мин 0,2а ?
Сетевой SNMP 5.0.х ?
OpenLDAP 2.1.х Да Используйте ldap_r вариант библиотеки для обеспечения потокобезопасности.
OpenSSL 0,9,6 г Да Требуется правильное использование CRYPTO_num_locks , CRYPTO_set_locking_callback , CRYPTO_set_id_callback
liboci8 (Оракул 8+) 8.х,9.х ?
pdflib 5.0.х Да Документы PDFLib утверждают, что это потокобезопасно; changes.txt указывает, что начиная с V1.91 он был частично потокобезопасным: http://www.pdflib.com/products/pdflib-family/pdflib/.
libpng 1.0.х ?
libpng 1.2.х ?
libpq (постгрес) 8.х Да Не делитесь соединениями между потоками и следите за crypt() звонками
Саблотрон 0,95 ?
zlib 1.1.4 Да Полагается на потокобезопасные функции zalloc и zfree. По умолчанию используются calloc/free из libc, которые являются потокобезопасными.


 <         > 

Пункты:   214    215    216    217    218    219    220    221    222      223    

Рейтинг@Mail.ru