Вход/Регистрация
Параллельное и распределенное программирование на С++
вернуться

Хьюз Камерон

Шрифт:

Синопсис

#include <pthread.h>

void pthread_cleanup_push(void (*routine)(void *),void *arg);

void pthread cleanup pop(int execute);

Параметр routine представляет собой указатель на функцию, помещаемый в стек завершающих процедур. Параметр arg содержит аргумент, передаваемый этой routine– функции, которая вызывается при завершении потока с помощью функции pthread_exit , когда поток «покоряется» запросу на аннулирование или явным образом вызывает функцию pthread__cleanup_pop с ненулевым значением параметра execute. Функция, заданная параметром routine, не возвращает никакого значения.

Функция pthread_cleanup_pop удаляет указатель routine– функции из вершины стека завершающих процедур вызывающего потока. Параметр execute может принимать значение 1 или 0. Если его значение равно 1, поток выполняет routine- функцию, даже если он при этом и не завершается. Поток продолжает свое выполнение с инструкции, расположенной за вызовом функции pthread_cleanup_pop. Если значение параметра execute равно 0, указатель извлекается из вершины стека потока без выполнения routine– функции.

Необходимо позаботиться о том, чтобы для каждой функции занесения в стек (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. В случае неудачи функция возвращает код ошибки.

  • Читать дальше
  • 1
  • ...
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: