Роб Кёртен - Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
- Название:Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
- Автор:
- Жанр:
- Издательство:Петрополис
- Год:2001
- Город:Санкт-Петербург
- ISBN:5-94656-025-9
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Роб Кёртен - Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform краткое содержание
Книга "Введение в QNX/Neutrino 2» откроет перед вами в мельчайших подробностях все секреты ОСРВ нового поколения от компании QNX Software Systems Ltd (QSSL) — QNX/Neutrino 2. Книга написана в непринужденной манере, легким для чтения и понимания стилем, и поможет любому, от начинающих программистов до опытных системотехников, получить необходимые начальные знания для проектирования надежных систем реального времени, от встраиваемых управляющих приложений до распределенных сетевых вычислительных систем
В книге подробно описаны основные составляющие ОС QNX/Neutrino и их взаимосвязи. В частности, уделено особое внимание следующим темам:
• обмен сообщениями: принципы функционирования и основы применения;
• процессы и потоки: базовые концепции, предостережения и рекомендации;
• таймеры: организация периодических событий в программах;
• администраторы ресурсов: все, что относится к программированию драйверов устройств;
• прерывания: рекомендации по эффективной обработке.
В книге представлено множество проверенных примеров кода, подробных разъяснений и рисунков, которые помогут вам детально вникнуть в и излагаемый материал. Примеры кода и обновления к ним также можно найти на веб-сайте автора данной книги, www.parse.com.
Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Очевидно, если вы переносите в QNX/Neutrino программу из другой ОС, вы пожелаете использовать те же механизмы, что и в исходной программе. Я бы посоветовал избегать в новом коде применения функции fork() , и вот почему:
• функция fork() не работает с несколькими потоками — см. выше;
• при работе с fork() в условиях многопоточности вы должны будете зарегистрировать обработчик pthread_atfork() и локировать каждый мутекс по отдельности перед собственно ветвлением, а это усложнит структуру программы;
• дочерние процессы, созданные fork() , копируют все открытые дескрипторы файлов. Как мы увидим позже в главе «Администратор ресурсов», это требует много дополнительных усилий, которые может быть совершенно напрасными, если дочерний процесс затем сразу сделает exec() и тем самым закроет все открытые дескрипторы.
Выбор между семействами функций vfork() и spawn() сводится к переносимости, а также того, что должны делать родительский и дочерний процесс. Функция vfork() задержит выполнение до тех пор, пока дочерний процесс не вызовет exec() или не завершится, тогда как семейство spawn() может позволить работать обоим процессам одновременно. Впрочем, в разных ОС поведение функции vfork() может несколько отличаться.
Запуск потока
Теперь, когда мы знаем, как запустить другой процесс, давайте рассмотрим, как осуществить запуск другого потока.
Любой поток может создать другой поток в том же самом процессе; на это не налагается никаких ограничений (за исключением объема памяти, конечно!) Наиболее общий путь реализации этого — использование вызова функций POSIX pthread_create() :
#include
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void*(*start_routine)(void*), void *arg);
Функция pthread_create() имеет четыре аргумента :
thread | указатель на pthread_t , где хранится идентификатор потока |
attr | атрибутная запись |
start_routine | подпрограмма, с которой начинается поток |
arg | параметр, который передается подпрограмме start_routine |
Отметим, что указатель thread и атрибутная запись ( attr ) — необязательные элементы, вы может передавать вместо них NULL.
Параметр thread может использоваться для хранения идентификатора вновь создаваемого потока. Обратите внимание, что в примерах, приведенных ниже, мы передадим NULL, обозначив этим, что мы не заботимся о том, какой идентификатор будет иметь вновь создаваемый поток.
Если бы нам было до этого дело, мы бы сделали так:
pthread_t tid;
pthread_create(&tid, ...
printf("Новый поток имеет идентификатор %d\n", tid);
Такое применение совершенно типично, потому что вам часто может потребоваться знать, какой поток выполняет какой участок кода.
Небольшой тонкий момент. Новый поток может начать работать еще до присвоения значения параметру tid . Это означает, что вы должны внимательно относиться к использованию tid в качестве глобальной переменной. В примере, приведенном выше, все будет корректно, потому что вызов pthread_create() отработал до использования tid , что означает, что на момент использования tid имел корректное значение.
Новый поток начинает выполнение с функции start_routine() , с параметром arg .
Когда вы осуществляете запуск нового потока, он может следовать ряду четко определенных установок по умолчанию, или же вы можете явно задать его характеристики.
Прежде, чем мы перейдем к обсуждению задания атрибутов потока, рассмотрим тип данных pthread_attr_t
:
typedef struct {
int flags;
size_t stacksize;
void *stackaddr;
void (*exitfunc)(void *status);
int policy;
struct sched_param param;
unsigned guardsize;
} pthread_attr_t;
В основном эти поля используются как:
flags | Неисчисляемые (булевы) характеристики потока — например, создается поток как «обособленный» или «синхронизирующий». |
stacksize , stackaddr и guardsize | Параметры стека. |
exitfunc | Функция, выполняемая перед завершением потока. |
policy и param | Параметры диспетчеризации. |
Доступны следующие функции:
Управление атрибутами
pthread_attr_destroy()
pthread_attr_init()
Флаги (булевы характеристики)
pthread_attr_getdetachstate()
pthread_attr_setdetachstate()
pthread_attr_getinheritsched()
pthread_attr_setinheritsched()
pthread_attr_getscope()
pthread_attr_setscope()
Параметры стека
pthread_attr_getguardsize()
pthread_attr_setguardsize()
pthread_attr_getstackaddr()
pthread_attr_setstackaddr()
pthread_attr_getstacksize()
pthread_attr_setstacksize()
Параметры диспетчеризации
pthread_attr_getschedparam()
pthread_attr_setschedparam()
pthread_attr_getschedpolicy()
pthread_attr_setschedpolicy()
Список выглядит довольно большим (18 функций), но в действительности нас будет заботить применение только примерно половины функций из этого списка, потому что все эти они сгруппированы по парам «get» — «set», т.е. в каждой паре есть функция как получения параметров (get), так и их установки (set) — за исключением функций pthread_attr_init() и pthread_attr_destroy() .
Прежде чем мы исследуем назначения атрибутов, следует отметить одно обстоятельство. Вы обязаны вызвать pthread_attr_init() для инициализации атрибутной записи до момента ее использования, задействовать ее с помощью соответствующей функции (функций) pthread_attr_set*() и только затем вызвать функцию pthread_create() для создания потока. Изменение атрибутной записи после того, как поток уже создан, не будет иметь никакого действия.
Перед использованием атрибутной записи для ее инициализации следует вызвать функцию pthread_attr_init() :
...
pthread_attr_t attr;
...
pthread_attr_init(&attr);
Вы можете также вызывать pthread_attr_destroy() для «деинициализации» атрибутной записи потока, но так обычно никто не делает (если не требуется жесткой POSIX-совместимости).
В приведенных ниже описаниях значения по умолчанию помечены комментарием «(по умолчанию)».
Три функции — pthread_attr_setdetachstate() , pthread_attr_setinheritsched() и pthread_attr_setscope() — определяют, создается ли поток как «синхронизирующий» («joinable») или как «обособленный» (detached), наследует ли поток атрибуты диспетчеризации от создающего потока или использует атрибуты диспетчеризации, указанные в функциях pthread_attr_setschedparam() и pthread_attr_setschedpolicy() , и, наконец, имеет ли поток масштаб «системы» или «процесса».
Для создания «синхронизирующего» потока (это значит, что с завершением этого потока можно синхронизировать другой поток при помощи функции pthread_join() ), используется вызов:
Читать дальшеИнтервал:
Закладка: