#include
int SignalKill(uint32_t nd, pid_t pid,
int tid, int signo, int code, int value);
int SignalKill_r(uint32_t nd, pid_t pid, int tid, int signo,
int code int value);
где nd— дескриптор сетевого узла QNET, на котором будут разыскиваться pidи tid. Для посылки сигнала локальному процессу (потоку) можно для ndуказать 0, но лучше — определенную системой константу ND_LOCAL_NODE.
Примечание
Дескриптор узла в сети QNET — понятие относительное; он может быть получен, например, вызовом netmgr_strtond(). Но и здесь не все так просто:
• Дескриптор, соответствующий, скажем, узлу «host», полученный на узле «А», может иметь значение N, но дескриптор того же узла, полученный на узле «В», будет иметь уже значение M, то есть дескриптор узла — это «дескриптор сетевого узла X, как он видится с сетевого узла Y».
• Тот же дескриптор узла «host» может быть определен как имеющий значение N, но уже через несколько секунд он может «сменить» свое значение на M, то есть значения, полученные netmgr_strtond(), должны использоваться немедленно...
Эти и другие сложности относятся к особенностям программного использования QNET и требуют отдельного обстоятельного обсуждения. Однако они не являются предметом нашего текущего рассмотрения.
pid— PID процесса, которому направляется сигнал, pidможет иметь и отрицательное значение, при этом положительное значение ( -pid) идентифицирует группу процессов EGID, и сигнал будет отправлен всем процессам группы. При нулевом значении pidсигнал будет отправлен всем процессам группы процесса отправителя.
tid— 0 или TID потока, которому направляется сигнал. При указании tidсигнал будет доставляться только указанному потоку, а при tid= 0 — всем потокам процесса. Дальнейшая судьба сигнала в обоих случаях зависит от маскирования сигнала в потоке, как мы рассматривали ранее.
signo— номер сигнала (с ним неоднократно встречались выше).
codeи value— код и значение, ассоциированные с сигналом (их мы тоже встречали при рассмотрении модели сигналов реального времени).
Как и обычно, внешнее различие (для программиста) основной формы SignalKill()и формы, безопасной в многопоточной среде, SignalKill_r()состоит в том, что:
• SignalKill()возвращает -1 в случае ошибки, а код ошибки заносится в errno; любой другой возврат является индикатором успешного выполнения;
• SignalKill_r()возвращает EOKв случае успеха, а в случае ошибки возвращается отрицательный код ошибки (тот же, который основная форма заносит в errno, но со знаком минус).
Возможны следующие коды ошибок, возвращаемые этими вызовами:
EINVAL— недопустимое числовое значение signo;
ESRCH— несуществующий адресат ( pidили tid);
EPERM— процесс не имеет достаточных прав для посылки сигнала;
EAGAIN— недостаточно ресурсов ядра для выполнения запроса.
Для того чтобы получить работающий пример использования этой возможности, возьмите любой из приводившихся выше примеров, разнесите процессы по сетевым узлам и определите «целеуказание» в процессе-отправителе.
Простейшим примером и демонстрацией удаленной реакции в сети может быть следующая последовательность действий:
• Производим запуск задачи на удаленномузле, например:
# on -f raqc
• После чего, выполнив ряд операций в запущенной программе, прекращаем ее работу по [Ctrl+C] с локального терминала.
Интересно оценить далеко идущие последствия этого «маленького» расширения стандартной POSIX-схемы работы с сигналами:
• На технике «сетевых сигналов» может быть построена целая система уведомлений сетевых составляющих компонент единой программной прикладной системы.
• Именно «уведомлений» (но не синхронизации с наследованием приоритетов, влияющей на общую систему диспетчеризации составляющих частей и т.п.): посылка сигнала является неблокирующей операцией (не требует ответа), а прием сигнала не сопровождается наследованием (или любым изменением) приоритетов.
• Такое «сигнальное» взаимодействие, записанное в формальной POSIX-семантике (но, по сути, осуществляющее механизмы, далеко выходящие за POSIX), может оказаться гораздо проще в записи и понимании, чем при использовании низкоуровневых механизмов обмена сообщениями (пульсами).
4. Примитивы синхронизации
ОС QNX Neutrino предоставляет широкий набор элементов синхронизации выполнения потоков, как в рамках одного процесса, так и разных. Это практически полный спектр примитивов, описываемых как базовым стандартом POSIX, так и всеми его расширениями реального времени. Тем не менее при работе со всеми этими примитивами не покидает ощущение, что некоторые из них являются органичными для самой ОС (мьютекс, условная переменная), в то время как другие — достаточно громоздкая надстройка над базовыми механизмами, реализуемая, главным образом, в угоду POSIX.
Читать дальше
Конец ознакомительного отрывка
Купить книгу