Проблема с асинхронной отменой заключается в том, что, хотя обработчики очистки ресурсов по-прежнему запускаются, они не могут определить состояние потока. В программе из листинга 32.2, в которой применяется отложенная отмена, поток может быть отменен только при вызове pthread_cond_wait() — единственной точки отмены. На этом этапе мы уже знаем, что переменная buf уже была инициализирована с помощью адреса блока выделенной памяти и что мьютекс mtx был закрыт. Но асинхронная отмена может произойти в любой момент; например, между вызовом malloc() и закрытием мьютекса или до/после этих событий. Обработчик очистки ресурсов не может узнать, где именно произошла отмена или какие именно ресурсы нужно освободить. Более того, поток может быть отменен даже во время вызова malloc(), что, скорее всего, приведет к непредвиденным результатам (см. подраздел 7.1.3).

В целом, асинхронно отменяемые потоки не могут выделять никаких ресурсов или владеть мьютексами, семафорами или блокировками. Это делает невозможным использование целого ряда библиотечных функций, включая большую часть содержимого библиотеки Pthreads (для функций pthread_cancel(), pthread_setcancelstate() и pthread_setcanceltype() в стандарте SUSv3 сделано исключение, так как они обязаны быть безопасными в условиях асинхронной отмены; то есть они должны быть реализованы так, чтобы их можно было безопасно вызывать из асинхронно отменяемого потока). Иными словами, существует несколько случаев, когда асинхронная отмена может оказаться полезной. Это, например, относится к отмене потока, находящегося в вычислительном цикле.

32.7. Резюме

Функция pthread_cancel() позволяет потокам отправлять друг другу запрос отмены, в результате которого поток должен быть завершен.

Реакцию потока на полученный запрос определяет его состояние и тип отмены. Если поток нельзя отменить, запрос будет отложен до тех пор, пока состояние потока не измениться. Если поток является отменяемым, реакция на запрос определяется типом его отмены. Если отмена отложенная, поток будет отменен при достижении одной из функций, которые определены стандартом SUSv3 в качестве точек отмены. Если отмена асинхронная, поток может быть отменен в любой момент (что редко бывает полезным).

Поток может иметь стек обработчиков для освобождения ресурсов; это функции, объявляемые программистом, которые в случае отмены потока автоматически вызываются для проведения очистки (то есть для восстановления состояния разделяемых переменных или открытия мьютексов).

Дополнительная информация

Ознакомьтесь с источниками, приведенными в разделе 29.10.

<p>33. Потоки выполнения: дальнейшие подробности</p>

В этой главе продолжается рассмотрение различных аспектов POSIX-потоков. Мы обсудим их взаимодействие в контексте традиционных программных интерфейсов UNIX — в частности, с помощью сигналов и средств управления процессами (fork(), exec() и _exit()). Здесь также будет представлен краткий обзор двух реализаций POSIX-потоков, доступных в Linux, — LinuxThreads и NPTL и их расхождения со спецификацией Pthreads, описанной в стандарте SUSv3.

33.1. Стеки потоков

Каждый поток имеет свой собственный стек фиксированного размера, который определяется при его создании. На платформе Linux/x86-32 размер стека во всех потоках, кроме главного, по умолчанию равен 2 Мбайт (в некоторых 64-битных архитектурах стандартный размер выше; например, в системах IA-64 он достигает 32 Мбайт). Главному потоку под стек выделяется намного больше места (см. рис. 29.1).

Иногда бывает полезно изменить размер стека, принадлежащего потоку. Это делается с помощью функции pthread_attr_setstacksize(), которая устанавливает атрибут потока (см. раздел 29.8), определяющий размер стека. Связанная с ней функция pthread_attr_setstack() позволяет управлять как размером, так и местоположением стека, хотя изменение последнего может негативно сказаться на переносимости приложения. Подробности об этих функциях ищите на их справочных страницах.

Изменение размера стека, принадлежащего потоку, может понадобиться в случаях, когда потоку нужно выделять большие автоматические переменные или выполнять вложенные вызовы функций большой глубины (возможно, в результате рекурсии). Приложение также может уменьшить размер стека, чтобы иметь возможность создать большее количество потоков в рамках одного процесса. Например, на платформе x86-32 виртуальное адресное пространство, доступное пользователю, ограничено размером 3 Гбайт, а стандартный объем стека равен 2 Мбайт; следовательно, мы можем создать около 1500 потоков (точное число зависит от того, сколько виртуальной памяти выделено на сегменты с текстом и данными, на разделяемые библиотеки и т. д.). Минимальный размер стека, доступный в текущей системе, можно узнать с помощью вызова sysconf(_SC_THREAD_STACK_MIN). Для библиотеки NPTL на платформе Linux/x86-32 это значение равно 16384.

Перейти на страницу:

Похожие книги