Главная страница  Взаимодействие нетривиальных процессов 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 [ 31 ] 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

Листинг 5.6 (продолжение)

18 }

19 if (optind != argc - 1)

20 err quit( usage: mqreceive [ -n ] <nanie> ):

21 mqd = Mq open(argv[optind]. flags):

22 Mq getattr(mqd. &attr):

23 buff = Mailoc(attr.mq msgsize):

24 n = Mq receive(mqd. buff. attr.mq msgsize. &prio);

25 printfCread *ld bytes, priority = *u\n . (long) n. prio):

26 exit(O):

27 }

Параметр -n запрещает блокировку

14-17 Параметр командной строки -п отключает блокировку. При этом программа возвращает сообщение об ошибке, если в очереди нет сообщений.

Открытие очереди и получение атрибутов

21-25 Мы открываем очередь и получаем ее атрибуты, вызвав mq getattr. Нам обязательно нужно определить максимальный размер сообщения, потому что мы должны выделить буфер подходящего размера, чтобы вызвать mq recei ve. Программа выводит размер считываемого сообщения и его приоритет.

ПРИМЕЧАНИЕ -

Поскольку п имеет тип size t и мы не знаем, int это или long, мы преобразуем эту величину к типу long и используем строку формата %ld. В 64-разрядной реализации int будет 32-разрядным целым, а long и size t будут 64-разрядными целыми.

Воспользуемся обеими программами, чтобы проиллюстрировать использование поля приоритета. Solaris % mqcreate /testl

Solaris % mqgetattr /testl создаем очередь и смотрим на ее атрибуты

max #msgs = 128. max #bytes/msg = 1024. Currently on queue = 0 Solaris % mqsend /testl 100 99999 отправка с некорректным значением приоритета mq send error: Invalid argument

Solaris % mqsend /testl 100 6 100 байт, приоритет 6

Solaris % mqsend /testl 50 IB 50 байт, приоритет 18

Solaris % mqsend /testl 33 IB 33 байт, приоритет 18

Solaris % mqreceive /testl

read 50 bytes, priority = 18 возвращается старейшее сообщение с

Solaris % mqreceive /testl наивысшим приоритетом

read 33 bytes, priority - 18 Solaris % mqreceive /testl read 100 bytes, priority - 6

Solaris % mqreceive -n /testl отключаем блокировку и убеждаемся, что очередь пуста mqreceive error: Resource temporarily unavailable

Мы видим, что mq recei ve действительно возвращает старейшее сообщение с наивысшим приоритетом.



5.5. Ограничения очередей сообщений

Мы уже сталкивались с двумя ограничениями, устанавливаемыми для любой очереди в момент ее создания:

ш mq maxmsg - максимальное количество сообщений в очереди; Ш mq msgsize - максимальный размер сообщения.

Не существует каких-либо ограничений на эти значения, хотя в рассматриваемых реализациях необходимо наличие в файловой системе места для файла требуемого размера. Кроме того, ограничения на эти величины могут накладываться реализацией виртуальной памяти (см. упражнение 5.5).

Другие два ограничения определяются реализацией:

Ш MQ OPEN MAX - максимальное количество очередей сообщений, которые могут быть одновременно открыты каким-либо процессом (Posix требует, чтобы эта величина была не меньше 8);

i> MQ PRIO MAX - максимальное значение приоритета плюс один (Posix требует, чтобы эта величина была не меньше 32).

Эти две константы часто определяются в заголовочном файле <uni std. h> и могут быть получены во время выполнения программы вызовом функции sysconf, как мы покажем далее.

Пример: программа mqsysconf

Программа в листинге 5.7 вызывает функцию sysconf и выводит два ограничения на очереди сообщений, определяемые реализацией.

Листинг 5.7. Получение ограничений очередей с помощью sysconf

pxmsg/mqsysconf.с

1 #include unpipc.h

2 int

3 mainCint argc. char **argv)

5 printfС MQ OPEN MAX = %й. MQ PRIO MAX = ld\n .

6 SysconfC SC MQ OPEN MAX). SysconfC SC MQ PRIO MAX)):

7 exitCO):

Запустив эту программу в наших двух операционных системах, получим:

Solaris % mqsysconf

MQ OPEN MAX = 32. MQ PRIO MAX = 32

alpha % mqsysconf

MQ OPEN MAX - 64. MQ PRIO MAX - 256

5.6. Функция mq notify

Один из недостатков очередей сообщений System V, как мы увидим в главе 6, заключается в невозможности зедомить процесс о том, что в очередь было помещено сообщение. Мы можем заблокировать процесс при вызове msgrcv, но тогда



мы не сможем выполнять другие действия во время ожидания сообщения. Если мы укажем флаг отключения блокировки при вызове msgrcv (IPC NOWAIT), процесс не будет заблокирован, но нам придется регулярно вызывать эту функцию, чтобы получить сообщение, когда оно будет отправлено. Мы уже говорили, что такая процедура называется опросом и на нее тратится лишнее время. Нужно, чтобы система сама уведомляла процесс о том, что в пустую очередь было помещено новое сообщение.

ПРИМЕЧАНИЕ -

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

Очереди сообщений Posix допускают асинхронное уведомление о событии, когда сообщение помещается в очередь. Это уведомление может быть реализовано либо отправкой сигнала, либо созданием программного потока для выполнения указанной функции.

Мы включаем режим уведомления с помощью функции mq noti fy:

#include <mqueue.li>

int mq notify(niqd t mqdes. const struct sigevent *notification):

I* Возвращает 0 в случае успешного выполнения. -1 - в случае ошибки */

Эта функция включает и выключает асинхронное уведомление о событии для указанной очереди. Структура sigevent впервые появилась в стандарте Posix.l для сигналов реального времени, о которых более подробно рассказано в следующем разделе. Эта структура и все новые константы, относящиеся к сигналам, определены в заголовочном файле <signa1 .li>:

union sigval {

int sivaljnt: /* целое значение */ void *sival ptr: /* указатель */

struct sigevent {

int sigev not1fy: /* SIGEV {NONE.SIGNAL.THREAD} */

Int sigev s1gno: /* номер сигнала, если SIGEV SIGNAL */

union sigval sigev value: /* передается обработчику сигнала или потоку */

/* Следующие два поля определены для SIGEV THREAD */

void (*sigev notify function) (union sigval):

ptliread attr t *sigev noti fy attributes:

Мы вскоре приведем несколько примеров различных вариантов использования уведомления, но о правилах, действующих для этой функции всегда, можно упомянуть уже сейчас.

1. Если аргумент notification ненулевой, процесс ожидает уведомления при поступлении нового сообщения в указанную очередь, пустую на момент его поступления. Мы говорим, что процесс регистрируется на уведомление для данной очереди.

2. Если аргумент notification представляет собой нулевой указатель и процесс уже зарегистрирован на уведомление для данной очереди, то уведомление для него отключается.



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 [ 31 ] 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования.