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

ЖАНРЫ

UNIX: взаимодействие процессов

Стивенс Уильям Ричард

Шрифт:

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

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

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

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

явно, мы проверяем, что mq_maxmsg и mq_msgsize имеют положительные значения.

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

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

//my_pxmsg_mmap/mq_open.с

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

52 msgsize = MSGSIZE(attr->mq_msgsize);

53 filesize = sizeof(struct mymq_hdr) + (attr->mq_maxmsg *

54 (sizeof(struct mymsg_hdr) + msgsize));

55 if (lseek(fd, filesize – 1, SEEK_SET) == –1)

56 goto err;

57 if (write(fd, "", 1) == –1)

58 goto err;

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

60 mptr = mmap(NULL, filesize, PROT_READ | PROT_WRITE,

61 MAP_SHARED, fd, 0);

62 if (mptr == MAP_FAILED)

63 goto err;

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

65 if ((mqinfo = mallос (sizeof (struct mymq_info))) == 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 mymq_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 mymsg_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->mqh_lock, &mattr);

93 pthread_mutexattr_destroy(&mattr); /* обязательно нужно удалить */

94 if (i != 0)

95 goto pthreaderr:

96 if ((i = pthread_condattr_init(&cattr)) != 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 Вычисляется размер сообщения, который затем округляется до кратного размеру длинного целого. Также в файле отводится место для структуры mq_hdr в начале файла и msghdr в начале каждого сообщения (рис. 5.2). Размер вновь созданного файла устанавливается функцией lseek и записью одного байта со значением 0. Проще было бы вызвать ftruncate (раздел 13.3), но у нас нет гарантий, что это сработало бы для увеличения размера файла.

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

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

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

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

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

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

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

88-102 Поскольку очереди сообщений Posix могут использоваться совместно произвольным количеством процессов, которые знают имя очереди и имеют соответствующие разрешения, нам нужно инициализировать взаимное исключение и условную переменную с атрибутом PTHREAD_PROCESS_SHARED. Для этого мы сначала инициализируем атрибуты вызовом pthread_mutexattr_init, а затем устанавливаем значение атрибута совместного использования процессами, вызвав pthread_mutexattr_setpshared. После этого взаимное исключение инициализируется вызовом pthread_mutex_init. Аналогичные действия выполняются для условной переменной. Мы должны аккуратно удалить взаимное исключение и условную переменную даже при возникновении ошибки, поскольку вызовы pthread_ mutexattr_init и pthread_condattr_init выделяют под них память (упражнение 7.3).

Поделиться с друзьями: