Чтение онлайн

на главную - закладки

Жанры

Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform

Кёртен Роб

Шрифт:

Я указал флаг POOL_FLAG_USE_SELF, что означает, что поток, вызвавший функцию thread_pool_start, будет рассматриваться как доступный для ввода в пул. Таким образом, на момент старта пула в нем есть только один поток. Поскольку значение параметра lo_water равно 3, библиотека немедленно создаст еще increment потоков (в нашем случае — 2). С этого момента в пуле будет три (3) потока, и все они будут находиться в режиме блокирования. Условие по параметру lo_water удовлетворено, потому что число потоков в режиме блокирования действительно не меньше lo_water, условие по параметру hi_water удовлетворено, потому что число потоков в режиме блокирования действительно не больше hi_water; и, наконец, также удовлетворено условие по параметру maximum, потому что общее число потоков не превышает его значения. Допустим теперь, что один из потоков, находящихся в режиме блокирования, разблокируется (например, в серверном приложении — при получении сообщения).

Это означает, что один из трех потоков перейдет из режима блокирования в режим обработки. Счетчик блокированных потоков уменьшится, и его значение упадет ниже значения параметра lo_water. Это переключит триггер lo_water и заставит библиотеку создать ещё increment (2) потоков. Таким образом, у нас будет всего 5 потоков (4 в режиме блокирования, и 1 — в режиме обработки).

Пусть далее разблокируется еще несколько потоков. Давайте предположим, что на этот момент еще ни один из потоков, находящихся в режиме обработки, еще не завершил свои дела. Ниже приведена таблица, в которой иллюстрируется весь процесс, начиная с исходного состояния:

Событие Режим обработки Режим блокирования Всего потоков
Исходное состояние 0 1 1
Срабатывание триггера lo_water 0 3 3
Разблокирование 1 2 3
Срабатывание триггера lo_water 1 4 5
Разблокирование 2 3 5
Разблокирование 3 2 5
Срабатывание триггера lo_water 3 4 7
Разблокирование 4 3 7
Разблокирование 5 2 7
Срабатывание триггера lo_water 5 4 9
Разблокирование 6 3 9
Разблокирование 7 2 9
Срабатывание триггера lo_water 7 3 10
Разблокирование 8 2 10
Разблокирование 9 1 10
Разблокирование 10 0 10

Видно, что библиотека проверяет параметр lo_water, и по мере необходимости увеличивает число потоков на значение параметра increment, но только до тех пор, пока число потоков не достигнет предельного значения — параметра maximum (именно поэтому число в столбце «Всего потоков» никогда не превышает 10, даже когда условие по параметру lo_water перестает выполняться).

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

Событие Режим обработки Режим блокирования Всего потоков
Завершение обработки 9 1 10
Завершение обработки 8 2 10
Завершение обработки 7 3 10
Завершение обработки 6 4 10
Завершение обработки 5 5 10
Завершение обработки 4 6 10
Завершение обработки 3 7 10
Завершение обработки 2 8 10
Срабатывание триггера hi_water 2 7 9
Завершение обработки 1 8 9
Срабатывание триггера hi_water 1 7 9
Завершение обработки 0 8 8
Срабатывание триггера hi_water 0 7 7

Обратите внимание, что с потоками ничего не происходит до тех пор, пока число блокированных потоков не превышает значение hi_water. Реализация здесь такова: как только поток завершает обработку, он проверяет число блокированных на данный момент потоков, и если их слишком много (то есть больше, чем предусмотрено параметром hi_water), то «совершает самоубийство». Удобство использования параметров lo_water и hi_water в управляющих структурах состоит в том, что ими вы фактически задаете «эффективный диапазон» числа потоков, в пределах которого всегда доступно достаточное число потоков, и потоки без необходимости не создаются и не уничтожаются. В нашем случае, после выполнения действий, перечисленных в вышеупомянутых таблицах, мы имеем систему, которая способна обрабатывать до 4 запросов одновременно без необходимости в создании дополнительных потоков (7-4 = 3, что соответствует значению параметра lo_ water).

Функции работы с пулами потоков

Теперь, когда мы достаточно хорошо владеем методикой управления числом потоков в пуле, давайте обратимся к другим элементам атрибутной записи пула потоков:

// Функции и дескриптор пула потоков

THREAD_POOL_HANDLE_T *handlе;

THREAD_POOL_PARAM_T *(*block_func)(

 THREAD_POOL_PARAM_T *ctp);

void (*unblock_func)(THREAD_POOL_PARAM_T *ctp);

int (*handler_func)(THREAD_POOL_PARAM_T *ctp);

THREAD_POOL_PARAM_T *(*context_alloc)(

 THREAD_POOL_HANDLE_T *handle);

void (*context_free)(THREAD_POOL_PARAM_T *ctp);

Повторно обратимся к рисунку «Жизненный цикл пула потоков». Из рисунка видно, что при создании потока каждый раз вызывается функция context_alloc. (Аналогично, при уничтожении потока вызывается функция context_tree). Элемент атрибутной записи с именем handler передается функции context_alloc в качестве ее единственного параметра. Функция context_alloc ответственна за индивидуальные настройки потока и возвращает указатель на контекст (списках параметров называемый ctp). Заметьте, что содержание этого указателя — исключительно ваша забота; библиотеке абсолютно все равно, что вы в него поместите.

Теперь, когда контекст создан функцией context_alloc, вызывается функция block_func для перевода потока в режим блокирования. Заметьте, что функция block_func получает на вход результат работы функции context_alloc. После того как функция block_func разблокируется, она возвращает указатель на контекст, который библиотека передает функции handler_func. Функция handler_func отвечает за выполнение «работы» — например, в типовом варианте именно она обрабатывает сообщение от клиента. На данный момент принято, что функция handler_func должна возвращать нуль — ненулевые значения зарезервированы QSSL для будущего функционального расширения. Функция unblock_func также в настоящее время зарезервирована, поэтому просто оставьте там NULL.

Возможно, ситуацию немного прояснит приведенный ниже пример псевдокода (он основан все на том же рисунке «Жизненный цикл потока в пуле потоков»):

FOREVER DO

 IF (#threads < lo_water) THEN

IF (#threads < maximum) THEN

create new thread

context = (*context_alloc)(handle);

ENDIF

 ENDIF

 retval = (*block_func)(context);

 (*handler_func)(retval);

 IF (#threads > hi_water) THEN

(*context_free)(context)

kill thread

 ENDIF

DONE

Отметим, что приведенная выше программа излишне упрощена. Ее назначение состоит только в том, чтобы продемонстрировать вам поток данных по параметрам ctp и handler и дать вам некоторое представление об алгоритмах, которые обычно применяются для управления числом потоков.

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

Я не Монте-Кристо

Тоцка Тала
Любовные романы:
современные любовные романы
5.57
рейтинг книги
Я не Монте-Кристо

Отмороженный 7.0

Гарцевич Евгений Александрович
7. Отмороженный
Фантастика:
рпг
аниме
5.00
рейтинг книги
Отмороженный 7.0

Истребители. Трилогия

Поселягин Владимир Геннадьевич
Фантастика:
альтернативная история
7.30
рейтинг книги
Истребители. Трилогия

Мама из другого мира. Делу - время, забавам - час

Рыжая Ехидна
2. Королевский приют имени графа Тадеуса Оберона
Фантастика:
фэнтези
8.83
рейтинг книги
Мама из другого мира. Делу - время, забавам - час

Мама из другого мира. Чужих детей не бывает

Рыжая Ехидна
Королевский приют имени графа Тадеуса Оберона
Фантастика:
фэнтези
8.79
рейтинг книги
Мама из другого мира. Чужих детей не бывает

Жена моего брата

Рам Янка
1. Черкасовы-Ольховские
Любовные романы:
современные любовные романы
6.25
рейтинг книги
Жена моего брата

Бастард

Осадчук Алексей Витальевич
1. Последняя жизнь
Фантастика:
фэнтези
героическая фантастика
попаданцы
5.86
рейтинг книги
Бастард

Ненастоящий герой. Том 1

N&K@
1. Ненастоящий герой
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Ненастоящий герой. Том 1

Бывший муж

Рузанова Ольга
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Бывший муж

Идеальный мир для Лекаря

Сапфир Олег
1. Лекарь
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря

Мастер 4

Чащин Валерий
4. Мастер
Фантастика:
героическая фантастика
боевая фантастика
попаданцы
5.00
рейтинг книги
Мастер 4

Адепт. Том второй. Каникулы

Бубела Олег Николаевич
7. Совсем не герой
Фантастика:
фэнтези
попаданцы
9.05
рейтинг книги
Адепт. Том второй. Каникулы

Кукловод

Злобин Михаил
2. О чем молчат могилы
Фантастика:
боевая фантастика
8.50
рейтинг книги
Кукловод

Ваше Сиятельство 3

Моури Эрли
3. Ваше Сиятельство
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Ваше Сиятельство 3