Примеры

Примеры

Этот раздел — своего рода «кулинарная книга» для программистов. Здесь я приведу ряд готовых примеров, которые вы сможете непосредственно использовать в качестве базиса для ваших проектов. Это не совсем готовые администраторы ресурсов — вы должны будете дополнить их функциями работы с пулами потоков и «каркасом» диспетчеризации (о котором речь ниже), а также удостовериться, что ваши версии функций- обработчиков помещаются в соответствующие таблицы функций после вызова iofunc_func_init(), чтобы корректно переопределить значения по умолчанию!

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

• io_read()

• io_write()

• io_devctl() (без передачи данных)

• io_devctl() (с передачей данных)

Затем, в разделе «Дополнительно», мы рассмотрим обработчик io_read(), который обеспечивает возврат элементов каталога.

Базовый каркас администратора ресурсов

Приведенный ниже пример можно использовать в качестве шаблона для многопоточного администратора ресурсов. (Шаблон однопоточного администратора ресурсов мы уже рассматривали — это было в разделе «Библиотека администратора ресурсов», когда мы обсуждали администратор /dev/null).

#include <stdio.h>

#include <stdlib.h>

#include <stddef.h>

#include <sys/iofunc.h>

#include <sys/dispatch.h>

static resmgr_connect_funcs_t connect_func;

static resmgr_io_funcs_t io_func;

static iofunc_attr_t attr;

main(int argc, char **argv) {

 thread_pool_attr_t pool_attr;

 thread_pool_t      *tpp;

 dispatch_t         *dpp;

 resmgr_attr_t      resmgr_attr;

 resmgr_context_t   *ctp;

 int                id;

 if ((dpp = dispatch_create()) == NULL) {

  fprintf(stderr,

   "%s: Ошибка выделения контекста диспетчеризации ",

   argv[0]);

  return (EXIT_FAILURE);

 }

 memset(&pool_attr, 0, sizeof(pool_attr));

 pool_attr.handle = dpp;

 pool_attr.context_alloc = resmgr_context_alloc;

 pool_attr.block_func = resmgr_block;

 pool_attr.handler_func = resmgr_handler;

 pool_attr.context_free = resmgr_context_free;

 // 1) Настроить пул потоков

 pool_attr.lo_water = 2;

 pool_attr.hi_water = 4;

 pool_attr.increment = 1;

 pool_attr.maximum = 50;

 if ((tpp =

  thread_pool_create(&pool_attr, POOL_FLAG_EXIT_SELF))

   == NULL) {

  fprintf(stderr,

   "%s: Ошибка инициализации пула потоков ",

  argv[0]);

  return (EXIT_FAILURE);

 }

 iofunc_func_init(_RESMGR_CONNECT_NFUNCS, &connect_func,

  _RESMGR_IO_NFUNCS, &io_func);

 iofunc_attr_init(&attr, S_IFNAM | 0777, 0, 0);

 // 2) Переопределить функции установления соединения

 // и функции ввода/вывода, как надо

 memset(&resmgr_attr, 0, sizeof(resmgr_attr));

 resmgr_attr.nparts_max = 1;

 resmgr_attr.msg_max_size = 2048;

 // 3) Замените «/dev/whatever» на нужный префикс

 if ((id =

  resmgr_attach(dpp, &resmgr_attr, "/dev/whatever",

   _FTYPE_ANY,

   0, &connect_func, &io_func, &attr)) == -1) {

  fprintf(stderr, "%s: Ошибка регистрации префикса ",

   argv[0]);

  return (EXIT_FAILURE);

 }

 // Отсюда возврата не будет

 thread_pool_start(tpp);

}

Дополнительную информацию об интерфейсе диспетчеризации (т.е., о функции dispatch_create()), см. в справочном руководстве по Си-библиотеке (С Library Reference).

Этап 1

Здесь мы используем функции пула потоков для создания пула, который должен будет обслуживать сообщения в нашем администраторе ресурсов. Вообще говоря, я бы рекомендовал вам начать однопоточного администратора ресурсов, как мы это делали ранее в примере с администратором /dev/null. Как только базовая функциональность у вас заработает, вы сможете затем добавить многопоточность. Вам нужно будет задать параметры lo_water, hi_water, increment и maximum структуры pool_attr, как это было описано в главе «Процессы и потоки» в обсуждениях функций пула потоков.

Этап 2

Здесь мы дополняем администратор ресурсов нашими функциями. Эти функции представляют собой функции- обработчики сообщений, о которых мы только что говорили (например, io_read(), io_devctl(), и т.п.). Например, чтобы добавить свой собственный обработчиком для сообщения _IO_READ, указывающий на функцию my_io_read(), мы должны были бы добавить в программу такую строчку:

io_func.io_read = my_io_read;

Это переопределит элемент таблицы, инициализированный вызовом iofunc_func_init() и содержавший функцию POSIX-уровня по умолчанию, заменив его указателем на вашу функцию my_io_read().

Этап 3

Вы, вероятно, не захотите, чтобы ваш администратор ресурсов назывался /dev/whatever (букв. — «/dev/абы_что» — прим. ред.), так что вам придется выбрать для него соответствующее имя. Отметим, что привязка атрибутной записи (параметр attr) к регистрируемому префиксу осуществляется вызовом resmgr_attach() — если бы нам было надо, чтобы наш администратор обрабатывал несколько устройств, нам пришлось бы вызывать resmgr_attach() несколько раз, каждый раз с новой атрибутной записью, чтобы на этапе выполнения можно было отличить зарегистрированные префиксы друг от друга.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг:

Примеры

Из книги автора

Примеры Этот раздел — своего рода «кулинарная книга» для программистов. Здесь я приведу ряд готовых примеров, которые вы сможете непосредственно использовать в качестве базиса для ваших проектов. Это не совсем готовые администраторы ресурсов — вы должны будете


5.12.5 Примеры

Из книги автора

5.12.5 Примеры Программа на Рисунке 5.18 иллюстрирует искусственное использование каналов. Процесс создает канал и входит в бесконечный цикл, записывая в канал строку символов «hello» и считывая ее из канала. Ядру не нужно ни знать о том, что процесс, ведущий запись в канал,


12.18 Примеры

Из книги автора

12.18 Примеры Некоторые реализации программы nslookup позволяют рассмотреть сообщения более подробно. Ниже приводится результат запуска nslookup на хосте Йельского университета и указывается вывод детальной отладочной информации с помощью команды set d2.Запрос требовал


Примеры

Из книги автора

Примеры Теперь воспользуемся четырьмя только что написанными программами. Создадим очередь и поместим в нее три сообщения:solaris % msgcreate /tmp/no/such/fileftok error for pathname "tmp/no/such/file" and id 0: No such file or directorysolaris % touch /trap/test1solaris % msgcreate /tmp/test1solaris % msgsnd /tmp/test1 1 100solaris % msgsnd /tmp/test1 2 200solaris % msgsnd /tmp/test1 3


10.5. Простые примеры

Из книги автора

10.5. Простые примеры В этом разделе мы напишем несколько простых программ, работающих с именованными семафорами Posix. Эти программы помогут нам узнать особенности функционирования и реализации семафоров. Поскольку именованные семафоры Posix обладают по крайней мере


Примеры

Из книги автора

Примеры Для начала мы создадим именованный семафор в Digital Unix 4.0B и выведем его значение, устанавливаемое по умолчанию при инициализации:alpha % semcreate /tmp/test1alpha % ls-l /tmp/test1-rw-r--r-- 1 rstevens system 264 Nov 13 08:51 /tmp/test1alpha %semgetvalue /tmp/test1value = 1Аналогично очередям сообщений Posix система создает файл


Примеры

Из книги автора

Примеры Теперь мы продемонстрируем работу пяти приведенных выше программ и исследуем некоторые свойства семафоров System V:solaris % touch /tmp/richsolaris % semcreate –e /tmp/rich 3solaris % semsetvalues /tmp/rich 1 2 3solaris % semgetvalues /tmp/richsemval[0] = 1semval[1] = 2semval[2] = 3Сначала мы создали файл с именем /tmp/rich, который


Примеры

Из книги автора

Примеры Создадим объект разделяемой памяти с именем /tmp/myshm объемом 123 456 байт в системе Digital Unix 4.0B:alpha % shmcreate /tmp/myshm 123456alpha % ls –l /tmp/myshm-rw-r--r-- 1 rstevens system 123456 Dec 10 14:33 /tmp/myshmalpha % od –c /tmp/myshm0000000 *0361100Мы видим, что файл с указываемым при создании объекта разделяемой памяти


Примеры

Из книги автора

Примеры Создадим сегмент разделяемой памяти длиной 1234 байта в системе Solaris 2.6. Для идентификации сегмента используем полное имя нашего исполняемого файла shmget. Это имя будет передано функции ftok. Имя исполняемого файла сервера часто используется в качестве уникального


15.7. Примеры

Из книги автора

15.7. Примеры В этом разделе мы приведем примеры использования пяти только что описанных


* ПРИМЕРЫ *

Из книги автора

* ПРИМЕРЫ * b1_1_1.cxx #include ‹stream.hxx›main(){ cout ‹‹ "Hello, world ";}


Примеры

Из книги автора

Примеры Книга содержит множество примеров. Все примеры комментируются по мере их приведения, и все же кое-что следует пояснить заранее.Из приведенного выше примера с map видно, что я обычно опускаю директивы #include и игнорирую тот факт, что компоненты STL принадлежат


ПРИМЕРЫ

Из книги автора

ПРИМЕРЫ while(n++ < 100) printf(" %d %d ",n, 2*n + 1);while(fargo < 1000){ fargo = fargo + step;   step = 2 * step;}     В нашем последнем примере в цикле while используется "неопределенное" условие: мы не знаем заранее, сколько раз выполнится тело цикла перед тем, как выражение станет ложным. Во многих наших


Примеры

Из книги автора

Примеры Этот оператор устанавливает новое значение по умолчанию для домена BOOK_GROUP:ALTER DOMAIN BOOK_GROUP SET DEFAULT -1;В следующем операторе имя домена BOOK_GROUP заменяется на PUBL_GROUP:ALTER DOMAIN BOOK_GROUP TO


8.4.1 Примеры

Из книги автора

8.4.1 Примеры Описаниеint i; int *pi; int f (); int *fpi (); int (*pif) ();описывает целое i, указатель pi на целое, функцию f, возвращающую целое, функцию fpi , возвращающую указатель на целое, и указатель pif на функцию, возвращающую целое. Осбенно полезно сравнить последние две. Цепочка *fpi() есть *(fpi()),