Необходимо позаботиться о том, чтобы для каждой функции занесения в стек (push) существовала функция извлечения из стека (pop) в пределах одной и той же лексической области видимости. Например, для функции funcA() обязательно выполнение cleanup-обработчика при ее нормальном завершении или аннулировании:
void *funcA(void *X)
{
int *Tid;
Tid = new int;
// do some work
//...
pthread_cleanup_push(cleanup_funcA,Tid);
// do some more work
//...
pthread_cleanup_pop(0);
}
Здесь функция funcA() помещает указатель на обработчик cleanup_funcA() в стек завершающих процедур путем вызова функции pthread_cleanup_push(). Каждому обращению к этой функции должно соответствовать обращение к функции pthread_cleanup_pop().Если функции извлечения указателя из стека (pop-функции) передается значение 0, то извлечение из стека состоится, но без выполнения обработчика. Обработчик будет выполнен лишь при аннулировании потока, выполняющего функцию funcA().
Для функции funcB() также требуется cleanup-обработчик:
void *funcB(void *X)
{
int *Tid;
Tid = new int;
// do some work
//...
pthread_cleanup_push(cleanup_funcB,Tid);
// do some more work
//...
pthread_cleanup_pop(1);
}
Здесь функция funcB() помещает указатель на обработчик cleanup_funcB() в стек завершающих процедур. Отличие этого примера от предыдущего состоит в том, что функции pthread_cleanup_pop() передается параметр со значением 1, т.е. после извлечения из стека указателя на обработчик этот обработчик будет тут же выполнен. Необходимо отметить, что выполнение обработчика в данном случае состоится «при любой погоде», т.е. и при аннулировании потока, который обеспечивает выполнение функции funcB(), и при обычном его завершении. Обработчики- «уборщики», cleanup_funcA()и cleanup_funcB(), — это обычные функции, которые можно использовать для закрытия файлов, освобождения ресурсов, разблокирования мьютексов и пр.
Адресное пространство процесса делится на раздел кода, раздел статических данных, свободную память и раздел стеков. Стекам потоков выделяется область из стекового раздела процесса. Стек потока предназначен для хранения стекового фрейма, связанного с каждой процедурой (функцией), которая была вызвана, но еще не завершена. Стековый фрейм содержит временные переменные, локальные переменные, адреса точек возврата и любую другую дополнительную информацию, которая необходима потоку, чтобы найти «обратную дорогу» к ранее вызванным процедурам. При выходе из процедуры (функции) ее стековый фрейм извлекается из стека. Расположение фреймов в стеке схематично показано на рис. 4.12.
Предположим, что поток А (см. рис. 4.12) выполняет функцию task1() , которая создает некоторые локальные переменные, выполняет заданную обработку, а затем вызывает функцию taskX(). При этом для функции task1() создается стековый фрейм, который помещается в стек потока. Функция taskX() выполняет «свои» действия, создает локальные переменные, а затем вызывает функцию taskC(). Нетрудно догадаться, что стековый фрейм, созданный для функции taskX() , также помещается в стек. Функция taskC() вызывает функцию taskY()и т.д. Каждый стек должен иметь достаточно большой размер, чтобы поместить всюинформацию, необходимую для выполнения всех функций потока, а также цепочки других подпрограмм, которые будут вызваны потоковыми функциями. Размером и местоположением стека потока управляет операционная система, но для установки и считывания этой информации предусмотрены методы, которые определены в объекте атрибутов потока.
Рис. 4.12. Стековые фреймы, сгенерированные потоками
Функция pthread_attr_getstacksize() возвращает минимальный размер стека, устанавливаемый по умолчанию. Параметр attrопределяет объект атрибутов потока, из которого считывается стандартный размер стека. При успешном выполнении функция возвращает значение 0, а стандартный размер стека, выраженный в байтах, coxpaняется в параметре stacksize. В случае неудачи функция возвращает код ошибки.
Функция pthread_attr_setstacksize()устанавливает минимальный размер стека. Параметр attrопределяет объект атрибутов потока, для которого устанавливается размер стека. Параметр stacksizeсодержит минимальный размер стека, выраженный в байтах. При успешном выполнении функция возвращает значение 0 ,в противном случае - код ошибки. Функция завершается неудачно, если значение параметра stacksizeоказывается меньше значения PTHREAD_MIN_STACKили превышает системный минимум. Вероятно, значение PTHREAD_STACK_MINбудет меньше минимального размера стека, возвращаемого функцией p thread_attr_getstacksize().Прежде чем увеличивать минимальный размер стека потока, следует поинтересоваться значением, возвращаемым функцией p thread_attr_getstacksize() р азмер ст ека фиксируется, чтобы его расширение во время выполнения программы ограничивалось рамками фиксированного пространства стека, установленного во время компиляции.
Читать дальше