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

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

Запустив сервер, мы увидим, что немедленно произойдет специальный вызов:

Solaris X serverunrefl /tmp/doorl

door unreferenced

Если мы проследим за значением счетчика открытых дескрипторов, мы увидим, что он становится равен 1 после возврата из cloor create и 2 после возврата из fattach. Вызов с1 ose уменьшает количество открытых дескрипторов с двух до одного, что приводит к специальному вызову процедуры. Единственная оставшаяся ссылка при этом представляет собой имя в файловой системе, а этого клиенту достаточно, чтобы обратиться к двери. Поэтому клиент продолжает работать правильно:

solarise clientunrefl /tmp/doorl 11

result: 121

Solaris X clientunrefl /tmp/doorl 22

result: 484

Более того, дальнейших специальных вызовов серверной процедуры не происходит. Для каждой двери осуществляется только один специальный вызов.

Теперь изменим нашу программу-сервер обратно, убрав вызов close для дескриптора двери. Процедура сервера и функция та i п приведены в листинге 15.14.

Листинг 15.14. Сервер, не закрывающий дескриптор двери

doors/serverunref2.c

1 finclude unpipc.h

2 void

3 servprocCvoid *cookie. char *dataptr, size t datasize.

4 door desc t *descptr. size t ndesc)

6 long arg. result:

7 if Cdataptr == DOOR UNREF DATA) {

8 printfС door unreferenced\n ):

9 Door return(NULL. 0. NULL. 0):

10 }

11 arg = *CClong *) dataptr):

12 printfC thread id ХЫ. arg = ld\n . prJhreadJdCNULL). arg):

13 sleepC6):

14 result = arg * arg:

15 printfC thread id *ld returning\n . pr thread idCNULL));

16 Door return(Cchar *) &result. sizeofCresult), NULL, 0):

17 }

18 int

19 mainCint argc, char **argv)

20 {

21 int fd:

23 if Cargc != 2)

24 err quitC usage: serverl <server-pathname> ):

25 /* создание двери, дескриптора и подключение к файлу */ , л

продолжение -Af



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

26 fd = Door create(servproc, NULL. DOOR UNREF);

27 unlink(argv[l]):

28 Close(Open(argv[l], 0 CREAT 0 RDWR, FILE MODE)):

29 FattachCfd, argv[l]):

30 /* servprocC) обрабатывает все запросы клиентов */

31 for С : ; )

32 pauseC);

33 }

Мы оставляем 6-секундную паузу и выводим сообщение о возврате из процедуры сервера. Запустим сервер в одном окне, а из другого проверим существование имени файла двери в файловой системе и удалим его с помощью ггл:

Solaris X is -1 /tmp/door2

Drw-r--r-- 1 rstevens otherl 0 Apr 16 08:58 /tmp/door2

Solaris % rm /tmp/door2

После удаления имени файла происходит специальный вызов процедуры сервера:

Solaris X serverunref2 /tmp/door2

door unreferenced после удаления файла из файловой системы

Если мы проследим за количеством ссылок на эту дверь, то увидим следующее: одна ссылка появляется после вызова cloor create, вторая - после fattach. После удаления файла с помощью ггл количество ссылок снова уменьшается до единицы, что приводит к специальному вызову процедуры.

В последнем примере использования этого атрибута мы снова удалим имя из файловой системы. Но на этот раз мы сначала запустим три экземпляра программы-клиента. Специальный вызов процедуры произойдет только после завершения последнего клиента, потому что каждый экзепляр клиента увеличивает количество ссылок на дверь. Используем сервер из листинга 15.14 и клиент из листинга 15.2.

Solaris X clientunref2 /tmp/door2 44 & clientunref2 /tmp/door2 55 & clientunref2 /tmp/ door2 55 &

[2] 13552 [3] 13553 [4] 13554

Solaris X rm /tmp/door2 клиенты все еще выполняются Solaris X result: 1936 result: 3025 result; 4356

Сервер при этом выведет вот что:

Solaris X serverunref2 /tmp/door2

thread id 4. arg = 44 thread id 5. arg = 55 thread id 6. arg = 66 thread id 4 returning thread id 5 returning thread id 6 returning door unreferenced

Проследим за значением счетчика открытых ссылок для этой двери. Он становится равным 1 после вызова cloor create, 2 после вызова fattach. Когда три



клиента вызывают open, счетчик увеличивается с 2 до 5. После удаления имени файла счетчик уменьшается до 4. После завершения работы трех клиентов счетчик уменьшается с 4 до 1 (последовательно), и последнее его изменение с 2 до 1 приводит к специальному вызову процедуры.

Этими примерами мы показали, что хотя описание атрибута DOOR UNREF выглядит просто ( специальный вызов происходит при изменении счетчика ссылок с 2 до 1 ), мы должны понимать принципы работы этого счетчика, чтобы им пользоваться.

15.8. Передача дескрипторов

Когда мы говорим о передаче открытого дескриптора от одного процесса другому, обычно подразумевается одно из двух:

Ш наследование всех открытых дескрипторов родительского процесса дочерним после вызова fork;

li сохранение открытых дескрипторов при вызове exec.

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

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

ПРИМЕЧАНИЕ-

Передача дескрипторов через доменные сокеты Unix была описана в разделе 14.7 [24]. В ядрах Berkeley и производных от них дескрипторы передаются именно через такие сокеты. Все подробности описаны в главе 18 [23]. В ядрах SVR4 используются другие методы передачи дескрипторов, а именно команды I SENDFD и I RECVFD функции ioctl. Они описаны в разделе 15.5.1 [21]. Но процесс в SVR4 может воспользоваться и механизмом доменных сокетов Unix.

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

Нужно понимать, что сервер не может просто записать в канал числовое значение дескриптора, как в следующем фрагменте кода:

int fd:

fd = Open (,..);

WriteCpipefd, &fd. sizeof(int)):



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