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

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

Обработка потенциальной ситуации гонок

35-40 Если бы при указании флага OCREAT мы просто открыли файл, отобразили его содержимое в память и проинициализировали отображенный файл (как будет описано ниже), у нас возникла бы ситуация гонок. Очередь сообщений инициализируется niq open только в том случае, если вызывающий процесс указывает флаг 0 CREAT и очередь сообщений еще не существует. Это означает, что нам нужно каким-то образом определять, существует она или нет. Для этого при открытии файла для последующего отображения в память мы всегда указываем флаг 0 EXCL. Возвращение ошибки EEXIST функцией open является ошибкой для mq open только в том случае, если при вызове был указан флаг 0 EXCL. В противном случае при возвращении функцией open ошибки EEXIST мы делаем вывод, что файл уже существует, и переходим к листингу 5.19, как если бы флаг 0 CREAT вовсе не был указан.

Ситуация гонок может возникнуть потому, что использование отображаемого в память файла для реализации очереди сообщений требует двух шагов при инициализации очереди; сначала файл должен быть создан функцией open, а затем его содержимое должно быть проинициализировано. Проблема возникает, если два потока (одного или различных процессов) вызывают niq open приблизительно одновременно. Один из потоков может создать файл, после чего управление будет передано системой второму потоку, прежде чем первый завершит инициализацию файла. Второй поток обнаружит, что файл уже существует (вызвав open с флагом 0 EXCL), и приступит к использованию очереди сообщений.

Мы используем бит user-execute для указания того, был ли проинициализи-рован файл с очередью сообщений. Этот бит устанавливается только тем потоком, который создает этот файл (флаг 0 EXCL позволяет определить этот поток); этот поток инициализирует файл с очередью сообщений, а затем сбрасывает бит user-execute.

Аналогичная ситуация может возникнуть в листингах 10.28 и 10.37.

Проверка атрибутов

42-50 Если при вызове в качестве последнего аргумента передан нулевой указатель, очередь сообщений инициализируется со значениями атрибутов по умолчанию: 128 сообщений в очереди и 1024 байта на сообщение. Если атрибуты указаны явно, мы проверяем, что niq maxmsg и mq msgsize имеют положительные значения.

Вторая часть функции mq open приведена в листинге 5.18. Она завершает инициализацию новой очереди сообщений.

Листинг 5.18. Вторая часть функции mq open: инициализация новой очереди

niy pxmsg mmap/mq open. с

51 /* вычисление и установка размера файла */

52 msgsize = MSGSIZE(attr->mq msgsize);

53 filesize = sizeofCstruct mymq hclr) + (attr->mq maxmsg *

54 (SizeofCstruct mymsg hclr) + msgsize)):

55 if (IseekCfd, filesize - 1, SEEKJET) == -1)

56 goto err:

57 if (writeCfd, 1) == -1)

58 goto err;



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

59 /* отображение фа11ла в память */

60 mptr - imapCNULL. filesize. PROT READ PROT WRITE.

61 IPJHARED, fd, 0);

62 if (mptr = IPJAILED)

63 goto err:

64 /* выделение структуры mymq info{} для очереди */

65 if ( (mqinfo = malloc(sizeof(struct mymqjnfo))) = NULL)

66 goto err:

67 mqinfo->mqi hdr = mqhdr = (struct mymq hdr *) mptr;

68 mqinfo->mqi magic - MQI MAGIC:

69 mqinfo->mqi flags = nonblock;

70 /* инициализация заголовка в начале файла */

71 /* создание списка пустых сообщений */

72 mqhdr->mqh attr.mq flags = 0:

73 mqhdr->mqh attr.mq maxmsg = attr->mq maxmsg:

74 mqhdr->mqh attr.mq msgsize = attr->mq msgsize:

75 mqhdr->mqh attr.mq curmsgs = 0:

76 mqhdr->mqh nwait = 0;

77 mqhdr->mqh pid = 0:

78 mqhdr->mqh head = 0:

79 index = sizeof (struct rnymq hdr):

80 mqhdr->mqh free = index;

81 for (i = 0; i < attr->mq maxmsg - 1: i++) {

82 msghdr = (struct mymsg hdr *) &mptr[index]:

83 index += sizeof(struct mymsg hdr) + msgsize;

84 msghdr->msg next = index;

85 }

86 msghdr = (struct rnymsg hdr *) &mptr[index];

87 msghdr->msg next = 0: /* конец списка пустых сообщений */

88 /* инициализация взаимного исключения и условной переменной */

89 if ( (i - pthread mutexattr init(&mattr)) !- 0)

90 goto pthreaderr:

91 pthread mutexattr setpshared(&mattr, PTHREAD PROCESS SHARED):

92 i = pthread mutex init(&mqhdr->mqhJock, &mattr):

93 pthread mutexattr destroy(&mattr): /* обязательно нужно удалить */

94 if (i != 0)

95 goto pthreaderr:

96 if ( (i - pthread condattr init(&cattr)) 1= 0)

97 goto pthreaderr:

98 pthread condattr setpshared(&cattr. PTHREAD PROCESS SHARED);

99 i = pthread cond init(&mqhdr->mqh wait. &cattr):

100 pthread condattr destroy(&cattr): /* обязательно нужно удалить */

101 if (i 0)

102 goto pthreaderr:

103 /* инициализация завершена, снимаем бит user-execute */

104 if (fchmod(fd. mode) == -1)

105 goto err;

106 close(fd):

107 return((mymqd t) mqinfo);

108 }



Установка размера файла

51-58 Вычисляется размер сообщения, который затем округляется до кратного размеру длинного целого. Также в файле отводится место для структуры niq hdr в начале файла и msg hdr в начале каждого сообщения (рис. 5.2). Размер вновь созданного файла устанавливается функцией 1 seek и записью одного байта со значением 0. Проще было бы вызвать ftruncate (раздел 13.3), но у нас нет гарантий, что это сработало бы для увеличения размера файла.

Отображение файла в память

59-63 Файл отображается в память функцией шар.

Выделение памяти под структуру mqjnfо

64-66 При каждом вызове mq open создается отдельный экземпляр mqj nf о. Эта структура после создания инициализируется.

Инициализация структуры nriq hdr

67-87 Инициализируется структура mq hdr. Заголовок связного списка сообщений (mqh head) инициализируется нулем, а все сообщения в очереди добавляются к списку свободных (mqh f гее).

Инициализация взаимного исключения и условной переменной

88-102 Поскольку очереди сообщений Posix могут использоваться совместно произвольным количеством процессов, которые знают имя очереди и имеют соответствующие разрешения, нам нужно инициализировать взаимное исключение и условную переменную с атрибутом PTHREAD PROCESS SHARED. Для этого мы сначала инициализируем атрибуты вызовом pthread mutexattr i ni t, а затем устанавливаем значение атрибута совместного использования процессами, вызвав pthread mutexattr setpshared. После этого взаимное исключение инициализируется вызовом pthread mutex i ni t. Аналогичные действия выполняются для условной переменной. Мы должны аккуратно удалить взаимное исключение и условную переменную даже при возникновении ошибки, поскольку вызовы pthread mutexattr i nit и pthread condattr i nit выделяют под них память (упражнение 7.3).

Сброс бита user-execute

103-107 После инициализации очереди сообщений мы сбрасываем бит user-execute. Это говорит другим процессам о том, что очередь была проинициализирована. Мы также закрываем файл вызовом с1 ose, поскольку он был успешно отображен в память и держать его открытым больше нет необходимости.

В листинге 5.19 приведен конец функции mq open, в котором осуществляется открытие существующей очереди сообщений.

Листинг 5.19. Третья часть функции mq open: открытие существующей очереди сообщений

rny pxnisg mmap/mq open. с

109 exists:

110 /* открытие файла и отображение его в память */

111 if ( (fd - open (pathname. 0 RDWR)) < 0) { продолжение-



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.
Копирование материалов разрешено исключительно при условии цититирования.